aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/icu/i18n
diff options
context:
space:
mode:
authormcheshkov <mcheshkov@yandex-team.ru>2022-02-10 16:46:15 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:46:15 +0300
commite9d19cec64684c9c1e6b0c98297e5b895cf904fe (patch)
tree2768b1223e96a8a0610a93d18425d9647c1123c8 /contrib/libs/icu/i18n
parent60040c91ffe701a84689b2c6310ff845e65cff42 (diff)
downloadydb-e9d19cec64684c9c1e6b0c98297e5b895cf904fe.tar.gz
Restoring authorship annotation for <mcheshkov@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/libs/icu/i18n')
-rw-r--r--contrib/libs/icu/i18n/alphaindex.cpp24
-rw-r--r--contrib/libs/icu/i18n/anytrans.cpp28
-rw-r--r--contrib/libs/icu/i18n/anytrans.h4
-rw-r--r--contrib/libs/icu/i18n/astro.cpp4
-rw-r--r--contrib/libs/icu/i18n/astro.h2
-rw-r--r--contrib/libs/icu/i18n/basictz.cpp2
-rw-r--r--contrib/libs/icu/i18n/bocsu.cpp4
-rw-r--r--contrib/libs/icu/i18n/bocsu.h8
-rw-r--r--contrib/libs/icu/i18n/brktrans.cpp16
-rw-r--r--contrib/libs/icu/i18n/brktrans.h4
-rw-r--r--contrib/libs/icu/i18n/buddhcal.cpp6
-rw-r--r--contrib/libs/icu/i18n/buddhcal.h4
-rw-r--r--contrib/libs/icu/i18n/calendar.cpp312
-rw-r--r--contrib/libs/icu/i18n/casetrn.cpp12
-rw-r--r--contrib/libs/icu/i18n/casetrn.h6
-rw-r--r--contrib/libs/icu/i18n/cecal.cpp2
-rw-r--r--contrib/libs/icu/i18n/cecal.h2
-rw-r--r--contrib/libs/icu/i18n/chnsecal.cpp6
-rw-r--r--contrib/libs/icu/i18n/chnsecal.h4
-rw-r--r--contrib/libs/icu/i18n/choicfmt.cpp4
-rw-r--r--contrib/libs/icu/i18n/coleitr.cpp4
-rw-r--r--contrib/libs/icu/i18n/coll.cpp42
-rw-r--r--contrib/libs/icu/i18n/collation.cpp2
-rw-r--r--contrib/libs/icu/i18n/collation.h2
-rw-r--r--contrib/libs/icu/i18n/collationbuilder.cpp4
-rw-r--r--contrib/libs/icu/i18n/collationbuilder.h2
-rw-r--r--contrib/libs/icu/i18n/collationcompare.cpp2
-rw-r--r--contrib/libs/icu/i18n/collationcompare.h2
-rw-r--r--contrib/libs/icu/i18n/collationdata.cpp2
-rw-r--r--contrib/libs/icu/i18n/collationdata.h2
-rw-r--r--contrib/libs/icu/i18n/collationdatabuilder.cpp4
-rw-r--r--contrib/libs/icu/i18n/collationdatabuilder.h2
-rw-r--r--contrib/libs/icu/i18n/collationdatareader.cpp6
-rw-r--r--contrib/libs/icu/i18n/collationdatareader.h2
-rw-r--r--contrib/libs/icu/i18n/collationdatawriter.cpp4
-rw-r--r--contrib/libs/icu/i18n/collationdatawriter.h2
-rw-r--r--contrib/libs/icu/i18n/collationfastlatin.cpp2
-rw-r--r--contrib/libs/icu/i18n/collationfastlatin.h2
-rw-r--r--contrib/libs/icu/i18n/collationfastlatinbuilder.cpp4
-rw-r--r--contrib/libs/icu/i18n/collationfastlatinbuilder.h2
-rw-r--r--contrib/libs/icu/i18n/collationfcd.cpp116
-rw-r--r--contrib/libs/icu/i18n/collationfcd.h2
-rw-r--r--contrib/libs/icu/i18n/collationiterator.cpp6
-rw-r--r--contrib/libs/icu/i18n/collationiterator.h36
-rw-r--r--contrib/libs/icu/i18n/collationkeys.cpp14
-rw-r--r--contrib/libs/icu/i18n/collationkeys.h2
-rw-r--r--contrib/libs/icu/i18n/collationroot.cpp2
-rw-r--r--contrib/libs/icu/i18n/collationroot.h2
-rw-r--r--contrib/libs/icu/i18n/collationrootelements.cpp2
-rw-r--r--contrib/libs/icu/i18n/collationrootelements.h2
-rw-r--r--contrib/libs/icu/i18n/collationruleparser.cpp10
-rw-r--r--contrib/libs/icu/i18n/collationruleparser.h2
-rw-r--r--contrib/libs/icu/i18n/collationsets.cpp2
-rw-r--r--contrib/libs/icu/i18n/collationsets.h2
-rw-r--r--contrib/libs/icu/i18n/collationsettings.cpp2
-rw-r--r--contrib/libs/icu/i18n/collationsettings.h2
-rw-r--r--contrib/libs/icu/i18n/collationtailoring.cpp2
-rw-r--r--contrib/libs/icu/i18n/collationtailoring.h4
-rw-r--r--contrib/libs/icu/i18n/collationweights.cpp6
-rw-r--r--contrib/libs/icu/i18n/collationweights.h4
-rw-r--r--contrib/libs/icu/i18n/collunsafe.h2
-rw-r--r--contrib/libs/icu/i18n/compactdecimalformat.cpp80
-rw-r--r--contrib/libs/icu/i18n/coptccal.cpp4
-rw-r--r--contrib/libs/icu/i18n/coptccal.h4
-rw-r--r--contrib/libs/icu/i18n/cpdtrans.cpp4
-rw-r--r--contrib/libs/icu/i18n/cpdtrans.h4
-rw-r--r--contrib/libs/icu/i18n/csdetect.cpp8
-rw-r--r--contrib/libs/icu/i18n/csdetect.h2
-rw-r--r--contrib/libs/icu/i18n/csmatch.cpp2
-rw-r--r--contrib/libs/icu/i18n/csmatch.h2
-rw-r--r--contrib/libs/icu/i18n/csr2022.cpp2
-rw-r--r--contrib/libs/icu/i18n/csr2022.h2
-rw-r--r--contrib/libs/icu/i18n/csrecog.cpp2
-rw-r--r--contrib/libs/icu/i18n/csrecog.h2
-rw-r--r--contrib/libs/icu/i18n/csrmbcs.cpp4
-rw-r--r--contrib/libs/icu/i18n/csrmbcs.h2
-rw-r--r--contrib/libs/icu/i18n/csrsbcs.cpp2
-rw-r--r--contrib/libs/icu/i18n/csrsbcs.h2
-rw-r--r--contrib/libs/icu/i18n/csrucode.cpp2
-rw-r--r--contrib/libs/icu/i18n/csrucode.h2
-rw-r--r--contrib/libs/icu/i18n/csrutf8.cpp2
-rw-r--r--contrib/libs/icu/i18n/csrutf8.h2
-rw-r--r--contrib/libs/icu/i18n/curramt.cpp8
-rw-r--r--contrib/libs/icu/i18n/currfmt.cpp12
-rw-r--r--contrib/libs/icu/i18n/currfmt.h4
-rw-r--r--contrib/libs/icu/i18n/currpinf.cpp324
-rw-r--r--contrib/libs/icu/i18n/currunit.cpp158
-rw-r--r--contrib/libs/icu/i18n/dangical.cpp4
-rw-r--r--contrib/libs/icu/i18n/dangical.h4
-rw-r--r--contrib/libs/icu/i18n/datefmt.cpp26
-rw-r--r--contrib/libs/icu/i18n/dayperiodrules.cpp6
-rw-r--r--contrib/libs/icu/i18n/dayperiodrules.h2
-rw-r--r--contrib/libs/icu/i18n/dcfmtsym.cpp188
-rw-r--r--contrib/libs/icu/i18n/decContext.cpp864
-rw-r--r--contrib/libs/icu/i18n/decContext.h2
-rw-r--r--contrib/libs/icu/i18n/decNumber.cpp16380
-rw-r--r--contrib/libs/icu/i18n/decNumber.h2
-rw-r--r--contrib/libs/icu/i18n/decNumberLocal.h18
-rw-r--r--contrib/libs/icu/i18n/decimfmt.cpp3328
-rw-r--r--contrib/libs/icu/i18n/double-conversion-bignum-dtoa.cpp1318
-rw-r--r--contrib/libs/icu/i18n/double-conversion-bignum-dtoa.h204
-rw-r--r--contrib/libs/icu/i18n/double-conversion-bignum.cpp1628
-rw-r--r--contrib/libs/icu/i18n/double-conversion-bignum.h340
-rw-r--r--contrib/libs/icu/i18n/double-conversion-cached-powers.cpp386
-rw-r--r--contrib/libs/icu/i18n/double-conversion-cached-powers.h164
-rw-r--r--contrib/libs/icu/i18n/double-conversion-diy-fp.h310
-rw-r--r--contrib/libs/icu/i18n/double-conversion-double-to-string.cpp900
-rw-r--r--contrib/libs/icu/i18n/double-conversion-double-to-string.h838
-rw-r--r--contrib/libs/icu/i18n/double-conversion-fast-dtoa.cpp1366
-rw-r--r--contrib/libs/icu/i18n/double-conversion-fast-dtoa.h212
-rw-r--r--contrib/libs/icu/i18n/double-conversion-ieee.h880
-rw-r--r--contrib/libs/icu/i18n/double-conversion-string-to-double.cpp1578
-rw-r--r--contrib/libs/icu/i18n/double-conversion-string-to-double.h488
-rw-r--r--contrib/libs/icu/i18n/double-conversion-strtod.cpp1252
-rw-r--r--contrib/libs/icu/i18n/double-conversion-strtod.h136
-rw-r--r--contrib/libs/icu/i18n/double-conversion-utils.h778
-rw-r--r--contrib/libs/icu/i18n/double-conversion.h92
-rw-r--r--contrib/libs/icu/i18n/dt_impl.h2
-rw-r--r--contrib/libs/icu/i18n/dtfmtsym.cpp96
-rw-r--r--contrib/libs/icu/i18n/dtitv_impl.h4
-rw-r--r--contrib/libs/icu/i18n/dtitvfmt.cpp550
-rw-r--r--contrib/libs/icu/i18n/dtitvinf.cpp144
-rw-r--r--contrib/libs/icu/i18n/dtptngen.cpp1786
-rw-r--r--contrib/libs/icu/i18n/dtptngen_impl.h64
-rw-r--r--contrib/libs/icu/i18n/dtrule.cpp2
-rw-r--r--contrib/libs/icu/i18n/erarules.cpp652
-rw-r--r--contrib/libs/icu/i18n/erarules.h198
-rw-r--r--contrib/libs/icu/i18n/esctrn.cpp4
-rw-r--r--contrib/libs/icu/i18n/esctrn.h4
-rw-r--r--contrib/libs/icu/i18n/ethpccal.cpp4
-rw-r--r--contrib/libs/icu/i18n/ethpccal.h4
-rw-r--r--contrib/libs/icu/i18n/fmtable.cpp162
-rw-r--r--contrib/libs/icu/i18n/fmtable_cnv.cpp2
-rw-r--r--contrib/libs/icu/i18n/fmtableimp.h10
-rw-r--r--contrib/libs/icu/i18n/format.cpp2
-rw-r--r--contrib/libs/icu/i18n/formatted_string_builder.cpp884
-rw-r--r--contrib/libs/icu/i18n/formatted_string_builder.h542
-rw-r--r--contrib/libs/icu/i18n/formattedval_impl.h552
-rw-r--r--contrib/libs/icu/i18n/formattedval_iterimpl.cpp352
-rw-r--r--contrib/libs/icu/i18n/formattedval_sbimpl.cpp414
-rw-r--r--contrib/libs/icu/i18n/formattedvalue.cpp464
-rw-r--r--contrib/libs/icu/i18n/fphdlimp.cpp44
-rw-r--r--contrib/libs/icu/i18n/fphdlimp.h96
-rw-r--r--contrib/libs/icu/i18n/fpositer.cpp10
-rw-r--r--contrib/libs/icu/i18n/funcrepl.cpp4
-rw-r--r--contrib/libs/icu/i18n/funcrepl.h4
-rw-r--r--contrib/libs/icu/i18n/gender.cpp8
-rw-r--r--contrib/libs/icu/i18n/gregocal.cpp40
-rw-r--r--contrib/libs/icu/i18n/gregoimp.cpp12
-rw-r--r--contrib/libs/icu/i18n/gregoimp.h28
-rw-r--r--contrib/libs/icu/i18n/hebrwcal.cpp4
-rw-r--r--contrib/libs/icu/i18n/hebrwcal.h4
-rw-r--r--contrib/libs/icu/i18n/indiancal.cpp72
-rw-r--r--contrib/libs/icu/i18n/indiancal.h10
-rw-r--r--contrib/libs/icu/i18n/inputext.cpp2
-rw-r--r--contrib/libs/icu/i18n/inputext.h2
-rw-r--r--contrib/libs/icu/i18n/islamcal.cpp12
-rw-r--r--contrib/libs/icu/i18n/islamcal.h4
-rw-r--r--contrib/libs/icu/i18n/japancal.cpp266
-rw-r--r--contrib/libs/icu/i18n/japancal.h42
-rw-r--r--contrib/libs/icu/i18n/listformatter.cpp1616
-rw-r--r--contrib/libs/icu/i18n/measfmt.cpp376
-rw-r--r--contrib/libs/icu/i18n/measunit.cpp2510
-rw-r--r--contrib/libs/icu/i18n/measunit_extra.cpp1786
-rw-r--r--contrib/libs/icu/i18n/measunit_impl.h424
-rw-r--r--contrib/libs/icu/i18n/measure.cpp6
-rw-r--r--contrib/libs/icu/i18n/msgfmt.cpp126
-rw-r--r--contrib/libs/icu/i18n/msgfmt_impl.h2
-rw-r--r--contrib/libs/icu/i18n/name2uni.cpp6
-rw-r--r--contrib/libs/icu/i18n/name2uni.h4
-rw-r--r--contrib/libs/icu/i18n/nfrlist.h4
-rw-r--r--contrib/libs/icu/i18n/nfrs.cpp50
-rw-r--r--contrib/libs/icu/i18n/nfrs.h12
-rw-r--r--contrib/libs/icu/i18n/nfrule.cpp144
-rw-r--r--contrib/libs/icu/i18n/nfrule.h12
-rw-r--r--contrib/libs/icu/i18n/nfsubs.cpp164
-rw-r--r--contrib/libs/icu/i18n/nfsubs.h8
-rw-r--r--contrib/libs/icu/i18n/nortrans.cpp4
-rw-r--r--contrib/libs/icu/i18n/nortrans.h4
-rw-r--r--contrib/libs/icu/i18n/nounit.cpp84
-rw-r--r--contrib/libs/icu/i18n/nultrans.cpp4
-rw-r--r--contrib/libs/icu/i18n/nultrans.h4
-rw-r--r--contrib/libs/icu/i18n/number_affixutils.cpp880
-rw-r--r--contrib/libs/icu/i18n/number_affixutils.h488
-rw-r--r--contrib/libs/icu/i18n/number_asformat.cpp234
-rw-r--r--contrib/libs/icu/i18n/number_asformat.h214
-rw-r--r--contrib/libs/icu/i18n/number_capi.cpp468
-rw-r--r--contrib/libs/icu/i18n/number_compact.cpp670
-rw-r--r--contrib/libs/icu/i18n/number_compact.h194
-rw-r--r--contrib/libs/icu/i18n/number_currencysymbols.cpp242
-rw-r--r--contrib/libs/icu/i18n/number_currencysymbols.h130
-rw-r--r--contrib/libs/icu/i18n/number_decimalquantity.cpp2694
-rw-r--r--contrib/libs/icu/i18n/number_decimalquantity.h1052
-rw-r--r--contrib/libs/icu/i18n/number_decimfmtprops.cpp304
-rw-r--r--contrib/libs/icu/i18n/number_decimfmtprops.h348
-rw-r--r--contrib/libs/icu/i18n/number_decnum.h158
-rw-r--r--contrib/libs/icu/i18n/number_fluent.cpp1536
-rw-r--r--contrib/libs/icu/i18n/number_formatimpl.cpp1072
-rw-r--r--contrib/libs/icu/i18n/number_formatimpl.h308
-rw-r--r--contrib/libs/icu/i18n/number_grouping.cpp218
-rw-r--r--contrib/libs/icu/i18n/number_integerwidth.cpp136
-rw-r--r--contrib/libs/icu/i18n/number_longnames.cpp700
-rw-r--r--contrib/libs/icu/i18n/number_longnames.h140
-rw-r--r--contrib/libs/icu/i18n/number_mapper.cpp1016
-rw-r--r--contrib/libs/icu/i18n/number_mapper.h502
-rw-r--r--contrib/libs/icu/i18n/number_microprops.h166
-rw-r--r--contrib/libs/icu/i18n/number_modifiers.cpp970
-rw-r--r--contrib/libs/icu/i18n/number_modifiers.h676
-rw-r--r--contrib/libs/icu/i18n/number_multiplier.cpp318
-rw-r--r--contrib/libs/icu/i18n/number_multiplier.h114
-rw-r--r--contrib/libs/icu/i18n/number_notation.cpp176
-rw-r--r--contrib/libs/icu/i18n/number_output.cpp94
-rw-r--r--contrib/libs/icu/i18n/number_padding.cpp192
-rw-r--r--contrib/libs/icu/i18n/number_patternmodifier.cpp660
-rw-r--r--contrib/libs/icu/i18n/number_patternmodifier.h508
-rw-r--r--contrib/libs/icu/i18n/number_patternstring.cpp2240
-rw-r--r--contrib/libs/icu/i18n/number_patternstring.h658
-rw-r--r--contrib/libs/icu/i18n/number_rounding.cpp882
-rw-r--r--contrib/libs/icu/i18n/number_roundingutils.h398
-rw-r--r--contrib/libs/icu/i18n/number_scientific.cpp354
-rw-r--r--contrib/libs/icu/i18n/number_scientific.h136
-rw-r--r--contrib/libs/icu/i18n/number_skeletons.cpp3462
-rw-r--r--contrib/libs/icu/i18n/number_skeletons.h704
-rw-r--r--contrib/libs/icu/i18n/number_types.h732
-rw-r--r--contrib/libs/icu/i18n/number_utils.cpp532
-rw-r--r--contrib/libs/icu/i18n/number_utils.h224
-rw-r--r--contrib/libs/icu/i18n/number_utypes.h100
-rw-r--r--contrib/libs/icu/i18n/numfmt.cpp216
-rw-r--r--contrib/libs/icu/i18n/numparse_affixes.cpp946
-rw-r--r--contrib/libs/icu/i18n/numparse_affixes.h450
-rw-r--r--contrib/libs/icu/i18n/numparse_compositions.cpp216
-rw-r--r--contrib/libs/icu/i18n/numparse_compositions.h248
-rw-r--r--contrib/libs/icu/i18n/numparse_currency.cpp378
-rw-r--r--contrib/libs/icu/i18n/numparse_currency.h148
-rw-r--r--contrib/libs/icu/i18n/numparse_decimal.cpp918
-rw-r--r--contrib/libs/icu/i18n/numparse_decimal.h152
-rw-r--r--contrib/libs/icu/i18n/numparse_impl.cpp730
-rw-r--r--contrib/libs/icu/i18n/numparse_impl.h222
-rw-r--r--contrib/libs/icu/i18n/numparse_parsednumber.cpp252
-rw-r--r--contrib/libs/icu/i18n/numparse_scientific.cpp326
-rw-r--r--contrib/libs/icu/i18n/numparse_scientific.h94
-rw-r--r--contrib/libs/icu/i18n/numparse_symbols.cpp396
-rw-r--r--contrib/libs/icu/i18n/numparse_symbols.h346
-rw-r--r--contrib/libs/icu/i18n/numparse_types.h542
-rw-r--r--contrib/libs/icu/i18n/numparse_utils.h86
-rw-r--r--contrib/libs/icu/i18n/numparse_validators.cpp170
-rw-r--r--contrib/libs/icu/i18n/numparse_validators.h190
-rw-r--r--contrib/libs/icu/i18n/numrange_fluent.cpp804
-rw-r--r--contrib/libs/icu/i18n/numrange_impl.cpp1016
-rw-r--r--contrib/libs/icu/i18n/numrange_impl.h226
-rw-r--r--contrib/libs/icu/i18n/numsys.cpp258
-rw-r--r--contrib/libs/icu/i18n/numsys_impl.h12
-rw-r--r--contrib/libs/icu/i18n/olsontz.cpp48
-rw-r--r--contrib/libs/icu/i18n/olsontz.h6
-rw-r--r--contrib/libs/icu/i18n/persncal.cpp6
-rw-r--r--contrib/libs/icu/i18n/persncal.h4
-rw-r--r--contrib/libs/icu/i18n/plurfmt.cpp70
-rw-r--r--contrib/libs/icu/i18n/plurrule.cpp736
-rw-r--r--contrib/libs/icu/i18n/plurrule_impl.h384
-rw-r--r--contrib/libs/icu/i18n/quant.cpp4
-rw-r--r--contrib/libs/icu/i18n/quant.h4
-rw-r--r--contrib/libs/icu/i18n/quantityformatter.cpp92
-rw-r--r--contrib/libs/icu/i18n/quantityformatter.h50
-rw-r--r--contrib/libs/icu/i18n/rbnf.cpp524
-rw-r--r--contrib/libs/icu/i18n/rbt.cpp10
-rw-r--r--contrib/libs/icu/i18n/rbt.h12
-rw-r--r--contrib/libs/icu/i18n/rbt_data.cpp2
-rw-r--r--contrib/libs/icu/i18n/rbt_data.h2
-rw-r--r--contrib/libs/icu/i18n/rbt_pars.cpp16
-rw-r--r--contrib/libs/icu/i18n/rbt_pars.h2
-rw-r--r--contrib/libs/icu/i18n/rbt_rule.cpp8
-rw-r--r--contrib/libs/icu/i18n/rbt_rule.h2
-rw-r--r--contrib/libs/icu/i18n/rbt_set.cpp2
-rw-r--r--contrib/libs/icu/i18n/rbt_set.h2
-rw-r--r--contrib/libs/icu/i18n/rbtz.cpp8
-rw-r--r--contrib/libs/icu/i18n/regexcmp.cpp612
-rw-r--r--contrib/libs/icu/i18n/regexcmp.h2
-rw-r--r--contrib/libs/icu/i18n/regexcst.h202
-rw-r--r--contrib/libs/icu/i18n/regeximp.cpp10
-rw-r--r--contrib/libs/icu/i18n/regeximp.h4
-rw-r--r--contrib/libs/icu/i18n/regexst.cpp136
-rw-r--r--contrib/libs/icu/i18n/regexst.h20
-rw-r--r--contrib/libs/icu/i18n/regextxt.cpp2
-rw-r--r--contrib/libs/icu/i18n/regextxt.h2
-rw-r--r--contrib/libs/icu/i18n/region.cpp94
-rw-r--r--contrib/libs/icu/i18n/region_impl.h2
-rw-r--r--contrib/libs/icu/i18n/reldatefmt.cpp878
-rw-r--r--contrib/libs/icu/i18n/reldtfmt.cpp14
-rw-r--r--contrib/libs/icu/i18n/reldtfmt.h4
-rw-r--r--contrib/libs/icu/i18n/rematch.cpp486
-rw-r--r--contrib/libs/icu/i18n/remtrans.cpp8
-rw-r--r--contrib/libs/icu/i18n/remtrans.h4
-rw-r--r--contrib/libs/icu/i18n/repattrn.cpp86
-rw-r--r--contrib/libs/icu/i18n/rulebasedcollator.cpp26
-rw-r--r--contrib/libs/icu/i18n/scientificnumberformatter.cpp18
-rw-r--r--contrib/libs/icu/i18n/scriptset.cpp24
-rw-r--r--contrib/libs/icu/i18n/scriptset.h10
-rw-r--r--contrib/libs/icu/i18n/search.cpp2
-rw-r--r--contrib/libs/icu/i18n/selfmt.cpp4
-rw-r--r--contrib/libs/icu/i18n/selfmtimpl.h2
-rw-r--r--contrib/libs/icu/i18n/sharedbreakiterator.cpp2
-rw-r--r--contrib/libs/icu/i18n/sharedbreakiterator.h2
-rw-r--r--contrib/libs/icu/i18n/sharedcalendar.h2
-rw-r--r--contrib/libs/icu/i18n/shareddateformatsymbols.h12
-rw-r--r--contrib/libs/icu/i18n/sharednumberformat.h2
-rw-r--r--contrib/libs/icu/i18n/sharedpluralrules.h2
-rw-r--r--contrib/libs/icu/i18n/simpletz.cpp34
-rw-r--r--contrib/libs/icu/i18n/smpdtfmt.cpp714
-rw-r--r--contrib/libs/icu/i18n/smpdtfst.cpp2
-rw-r--r--contrib/libs/icu/i18n/smpdtfst.h4
-rw-r--r--contrib/libs/icu/i18n/sortkey.cpp2
-rw-r--r--contrib/libs/icu/i18n/standardplural.cpp2
-rw-r--r--contrib/libs/icu/i18n/standardplural.h2
-rw-r--r--contrib/libs/icu/i18n/string_segment.cpp290
-rw-r--r--contrib/libs/icu/i18n/string_segment.h268
-rw-r--r--contrib/libs/icu/i18n/strmatch.cpp4
-rw-r--r--contrib/libs/icu/i18n/strmatch.h4
-rw-r--r--contrib/libs/icu/i18n/strrepl.cpp4
-rw-r--r--contrib/libs/icu/i18n/strrepl.h4
-rw-r--r--contrib/libs/icu/i18n/stsearch.cpp4
-rw-r--r--contrib/libs/icu/i18n/taiwncal.cpp4
-rw-r--r--contrib/libs/icu/i18n/taiwncal.h4
-rw-r--r--contrib/libs/icu/i18n/timezone.cpp186
-rw-r--r--contrib/libs/icu/i18n/titletrn.cpp14
-rw-r--r--contrib/libs/icu/i18n/titletrn.h4
-rw-r--r--contrib/libs/icu/i18n/tmunit.cpp6
-rw-r--r--contrib/libs/icu/i18n/tmutamt.cpp4
-rw-r--r--contrib/libs/icu/i18n/tmutfmt.cpp14
-rw-r--r--contrib/libs/icu/i18n/tolowtrn.cpp4
-rw-r--r--contrib/libs/icu/i18n/tolowtrn.h4
-rw-r--r--contrib/libs/icu/i18n/toupptrn.cpp4
-rw-r--r--contrib/libs/icu/i18n/toupptrn.h4
-rw-r--r--contrib/libs/icu/i18n/translit.cpp72
-rw-r--r--contrib/libs/icu/i18n/transreg.cpp216
-rw-r--r--contrib/libs/icu/i18n/transreg.h14
-rw-r--r--contrib/libs/icu/i18n/tridpars.cpp6
-rw-r--r--contrib/libs/icu/i18n/tridpars.h2
-rw-r--r--contrib/libs/icu/i18n/tzfmt.cpp110
-rw-r--r--contrib/libs/icu/i18n/tzgnames.cpp38
-rw-r--r--contrib/libs/icu/i18n/tzgnames.h4
-rw-r--r--contrib/libs/icu/i18n/tznames.cpp12
-rw-r--r--contrib/libs/icu/i18n/tznames_impl.cpp96
-rw-r--r--contrib/libs/icu/i18n/tznames_impl.h16
-rw-r--r--contrib/libs/icu/i18n/tzrule.cpp4
-rw-r--r--contrib/libs/icu/i18n/tztrans.cpp2
-rw-r--r--contrib/libs/icu/i18n/ucal.cpp80
-rw-r--r--contrib/libs/icu/i18n/ucln_in.cpp4
-rw-r--r--contrib/libs/icu/i18n/ucln_in.h16
-rw-r--r--contrib/libs/icu/i18n/ucol.cpp6
-rw-r--r--contrib/libs/icu/i18n/ucol_imp.h4
-rw-r--r--contrib/libs/icu/i18n/ucol_res.cpp36
-rw-r--r--contrib/libs/icu/i18n/ucol_sit.cpp152
-rw-r--r--contrib/libs/icu/i18n/ucoleitr.cpp2
-rw-r--r--contrib/libs/icu/i18n/ucsdet.cpp2
-rw-r--r--contrib/libs/icu/i18n/udat.cpp16
-rw-r--r--contrib/libs/icu/i18n/udateintervalformat.cpp96
-rw-r--r--contrib/libs/icu/i18n/udatpg.cpp52
-rw-r--r--contrib/libs/icu/i18n/ufieldpositer.cpp2
-rw-r--r--contrib/libs/icu/i18n/uitercollationiterator.cpp2
-rw-r--r--contrib/libs/icu/i18n/uitercollationiterator.h2
-rw-r--r--contrib/libs/icu/i18n/ulistformatter.cpp320
-rw-r--r--contrib/libs/icu/i18n/ulocdata.cpp772
-rw-r--r--contrib/libs/icu/i18n/umsg.cpp14
-rw-r--r--contrib/libs/icu/i18n/umsg_imp.h4
-rw-r--r--contrib/libs/icu/i18n/unesctrn.cpp4
-rw-r--r--contrib/libs/icu/i18n/unesctrn.h4
-rw-r--r--contrib/libs/icu/i18n/uni2name.cpp4
-rw-r--r--contrib/libs/icu/i18n/uni2name.h4
-rw-r--r--contrib/libs/icu/i18n/unum.cpp216
-rw-r--r--contrib/libs/icu/i18n/unumsys.cpp2
-rw-r--r--contrib/libs/icu/i18n/upluralrules.cpp210
-rw-r--r--contrib/libs/icu/i18n/uregex.cpp22
-rw-r--r--contrib/libs/icu/i18n/uregexc.cpp2
-rw-r--r--contrib/libs/icu/i18n/uregion.cpp2
-rw-r--r--contrib/libs/icu/i18n/usearch.cpp34
-rw-r--r--contrib/libs/icu/i18n/uspoof.cpp282
-rw-r--r--contrib/libs/icu/i18n/uspoof_build.cpp46
-rw-r--r--contrib/libs/icu/i18n/uspoof_conf.cpp72
-rw-r--r--contrib/libs/icu/i18n/uspoof_conf.h8
-rw-r--r--contrib/libs/icu/i18n/uspoof_impl.cpp118
-rw-r--r--contrib/libs/icu/i18n/uspoof_impl.h22
-rw-r--r--contrib/libs/icu/i18n/usrchimp.h2
-rw-r--r--contrib/libs/icu/i18n/utf16collationiterator.cpp2
-rw-r--r--contrib/libs/icu/i18n/utf16collationiterator.h2
-rw-r--r--contrib/libs/icu/i18n/utf8collationiterator.cpp68
-rw-r--r--contrib/libs/icu/i18n/utf8collationiterator.h2
-rw-r--r--contrib/libs/icu/i18n/utmscale.cpp232
-rw-r--r--contrib/libs/icu/i18n/utrans.cpp12
-rw-r--r--contrib/libs/icu/i18n/vtzone.cpp380
-rw-r--r--contrib/libs/icu/i18n/vzone.cpp2
-rw-r--r--contrib/libs/icu/i18n/vzone.h2
-rw-r--r--contrib/libs/icu/i18n/windtfmt.cpp214
-rw-r--r--contrib/libs/icu/i18n/windtfmt.h14
-rw-r--r--contrib/libs/icu/i18n/winnmfmt.cpp278
-rw-r--r--contrib/libs/icu/i18n/winnmfmt.h8
-rw-r--r--contrib/libs/icu/i18n/wintzimpl.cpp36
-rw-r--r--contrib/libs/icu/i18n/wintzimpl.h6
-rw-r--r--contrib/libs/icu/i18n/zonemeta.cpp46
-rw-r--r--contrib/libs/icu/i18n/zonemeta.h12
-rw-r--r--contrib/libs/icu/i18n/zrule.cpp2
-rw-r--r--contrib/libs/icu/i18n/zrule.h2
-rw-r--r--contrib/libs/icu/i18n/ztrans.cpp2
-rw-r--r--contrib/libs/icu/i18n/ztrans.h2
403 files changed, 49085 insertions, 49085 deletions
diff --git a/contrib/libs/icu/i18n/alphaindex.cpp b/contrib/libs/icu/i18n/alphaindex.cpp
index 9c312bd8e6..5d1fe2ff29 100644
--- a/contrib/libs/icu/i18n/alphaindex.cpp
+++ b/contrib/libs/icu/i18n/alphaindex.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -260,7 +260,7 @@ AlphabeticIndex::ImmutableIndex *AlphabeticIndex::buildImmutableIndex(UErrorCode
// but that would be worth it only if this method is called multiple times,
// or called after using the old-style bucket iterator API.
LocalPointer<BucketList> immutableBucketList(createBucketList(errorCode));
- LocalPointer<RuleBasedCollator> coll(collatorPrimaryOnly_->clone());
+ LocalPointer<RuleBasedCollator> coll(collatorPrimaryOnly_->clone());
if (immutableBucketList.isNull() || coll.isNull()) {
errorCode = U_MEMORY_ALLOCATION_ERROR;
return NULL;
@@ -510,8 +510,8 @@ BucketList *AlphabeticIndex::createBucketList(UErrorCode &errorCode) const {
ces, errorCode) &&
current.charAt(current.length() - 1) != 0xFFFF /* !current.endsWith("\uffff") */) {
// "AE-ligature" or "Sch" etc.
- for (int32_t j = bucketList->size() - 2;; --j) {
- Bucket *singleBucket = getBucket(*bucketList, j);
+ for (int32_t j = bucketList->size() - 2;; --j) {
+ Bucket *singleBucket = getBucket(*bucketList, j);
if (singleBucket->labelType_ != U_ALPHAINDEX_NORMAL) {
// There is no single-character bucket since the last
// underflow or inflow label.
@@ -607,8 +607,8 @@ BucketList *AlphabeticIndex::createBucketList(UErrorCode &errorCode) const {
}
// Do not call publicBucketList->setDeleter():
// This vector shares its objects with the bucketList.
- for (int32_t j = 0; j < bucketList->size(); ++j) {
- bucket = getBucket(*bucketList, j);
+ for (int32_t j = 0; j < bucketList->size(); ++j) {
+ bucket = getBucket(*bucketList, j);
if (bucket->displayBucket_ == NULL) {
publicBucketList->addElement(bucket, errorCode);
}
@@ -724,7 +724,7 @@ void AlphabeticIndex::addIndexExemplars(const Locale &locale, UErrorCode &status
}
// question: should we add auxiliary exemplars?
- if (exemplars.containsSome(0x61, 0x7A) /* a-z */ || exemplars.isEmpty()) {
+ if (exemplars.containsSome(0x61, 0x7A) /* a-z */ || exemplars.isEmpty()) {
exemplars.add(0x61, 0x7A);
}
if (exemplars.containsSome(0xAC00, 0xD7A3)) { // Hangul syllables
@@ -739,9 +739,9 @@ void AlphabeticIndex::addIndexExemplars(const Locale &locale, UErrorCode &status
// cut down to small list
// make use of the fact that Ethiopic is allocated in 8's, where
// the base is 0 mod 8.
- UnicodeSet ethiopic(UnicodeString(u"[ሀለሐመሠረሰሸቀቈቐቘበቨተቸኀኈነኘአከኰኸዀወዐዘዠየደዸጀገጐጘጠጨጰጸፀፈፐፘ]"), status);
- ethiopic.retainAll(exemplars);
- exemplars.remove(u'ሀ', 0x137F).addAll(ethiopic);
+ UnicodeSet ethiopic(UnicodeString(u"[ሀለሐመሠረሰሸቀቈቐቘበቨተቸኀኈነኘአከኰኸዀወዐዘዠየደዸጀገጐጘጠጨጰጸፀፈፐፘ]"), status);
+ ethiopic.retainAll(exemplars);
+ exemplars.remove(u'ሀ', 0x137F).addAll(ethiopic);
}
// Upper-case any that aren't already so.
@@ -906,7 +906,7 @@ void AlphabeticIndex::init(const Locale *locale, UErrorCode &status) {
return;
}
}
- collatorPrimaryOnly_ = collator_->clone();
+ collatorPrimaryOnly_ = collator_->clone();
if (collatorPrimaryOnly_ == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
@@ -957,7 +957,7 @@ collatorComparator(const void *context, const void *left, const void *right) {
}
if (leftString == NULL) {
return 1;
- }
+ }
if (rightString == NULL) {
return -1;
}
diff --git a/contrib/libs/icu/i18n/anytrans.cpp b/contrib/libs/icu/i18n/anytrans.cpp
index 167b018528..a1092301b5 100644
--- a/contrib/libs/icu/i18n/anytrans.cpp
+++ b/contrib/libs/icu/i18n/anytrans.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*****************************************************************
@@ -31,14 +31,14 @@
static const UChar TARGET_SEP = 45; // '-'
static const UChar VARIANT_SEP = 47; // '/'
-static const UChar ANY[] = {0x41,0x6E,0x79,0}; // "Any"
+static const UChar ANY[] = {0x41,0x6E,0x79,0}; // "Any"
static const UChar NULL_ID[] = {78,117,108,108,0}; // "Null"
-static const UChar LATIN_PIVOT[] = {0x2D,0x4C,0x61,0x74,0x6E,0x3B,0x4C,0x61,0x74,0x6E,0x2D,0}; // "-Latn;Latn-"
-
-// initial size for an Any-XXXX transform's cache of script-XXXX transforms
-// (will grow as necessary, but we don't expect to have source text with more than 7 scripts)
-#define ANY_TRANS_CACHE_INIT_SIZE 7
+static const UChar LATIN_PIVOT[] = {0x2D,0x4C,0x61,0x74,0x6E,0x3B,0x4C,0x61,0x74,0x6E,0x2D,0}; // "-Latn;Latn-"
+// initial size for an Any-XXXX transform's cache of script-XXXX transforms
+// (will grow as necessary, but we don't expect to have source text with more than 7 scripts)
+#define ANY_TRANS_CACHE_INIT_SIZE 7
+
//------------------------------------------------------------
U_CDECL_BEGIN
@@ -190,7 +190,7 @@ AnyTransliterator::AnyTransliterator(const UnicodeString& id,
Transliterator(id, NULL),
targetScript(theTargetScript)
{
- cache = uhash_openSize(uhash_hashLong, uhash_compareLong, NULL, ANY_TRANS_CACHE_INIT_SIZE, &ec);
+ cache = uhash_openSize(uhash_hashLong, uhash_compareLong, NULL, ANY_TRANS_CACHE_INIT_SIZE, &ec);
if (U_FAILURE(ec)) {
return;
}
@@ -216,7 +216,7 @@ AnyTransliterator::AnyTransliterator(const AnyTransliterator& o) :
{
// Don't copy the cache contents
UErrorCode ec = U_ZERO_ERROR;
- cache = uhash_openSize(uhash_hashLong, uhash_compareLong, NULL, ANY_TRANS_CACHE_INIT_SIZE, &ec);
+ cache = uhash_openSize(uhash_hashLong, uhash_compareLong, NULL, ANY_TRANS_CACHE_INIT_SIZE, &ec);
if (U_FAILURE(ec)) {
return;
}
@@ -226,7 +226,7 @@ AnyTransliterator::AnyTransliterator(const AnyTransliterator& o) :
/**
* Transliterator API.
*/
-AnyTransliterator* AnyTransliterator::clone() const {
+AnyTransliterator* AnyTransliterator::clone() const {
return new AnyTransliterator(*this);
}
@@ -290,7 +290,7 @@ Transliterator* AnyTransliterator::getTransliterator(UScriptCode source) const {
}
if (t == NULL) {
UErrorCode ec = U_ZERO_ERROR;
- UnicodeString sourceName(uscript_getShortName(source), -1, US_INV);
+ UnicodeString sourceName(uscript_getShortName(source), -1, US_INV);
UnicodeString id(sourceName);
id.append(TARGET_SEP).append(target);
@@ -391,12 +391,12 @@ void AnyTransliterator::registerIDs() {
UnicodeString id;
TransliteratorIDParser::STVtoID(UnicodeString(TRUE, ANY, 3), target, variant, id);
ec = U_ZERO_ERROR;
- AnyTransliterator* tl = new AnyTransliterator(id, target, variant,
+ AnyTransliterator* tl = new AnyTransliterator(id, target, variant,
targetScript, ec);
if (U_FAILURE(ec)) {
- delete tl;
+ delete tl;
} else {
- Transliterator::_registerInstance(tl);
+ Transliterator::_registerInstance(tl);
Transliterator::_registerSpecialInverse(target, UnicodeString(TRUE, NULL_ID, 4), FALSE);
}
}
diff --git a/contrib/libs/icu/i18n/anytrans.h b/contrib/libs/icu/i18n/anytrans.h
index 627dee3c81..162f06ea37 100644
--- a/contrib/libs/icu/i18n/anytrans.h
+++ b/contrib/libs/icu/i18n/anytrans.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
***********************************************************************
@@ -66,7 +66,7 @@ public:
/**
* Transliterator API.
*/
- virtual AnyTransliterator* clone() const;
+ virtual AnyTransliterator* clone() const;
/**
* Implements {@link Transliterator#handleTransliterate}.
diff --git a/contrib/libs/icu/i18n/astro.cpp b/contrib/libs/icu/i18n/astro.cpp
index f17b6db912..3458b90741 100644
--- a/contrib/libs/icu/i18n/astro.cpp
+++ b/contrib/libs/icu/i18n/astro.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/************************************************************************
* Copyright (C) 1996-2012, International Business Machines Corporation
@@ -65,7 +65,7 @@ static inline UBool isINVALID(double d) {
return(uprv_isNaN(d));
}
-static icu::UMutex ccLock;
+static icu::UMutex ccLock;
U_CDECL_BEGIN
static UBool calendar_astro_cleanup(void) {
diff --git a/contrib/libs/icu/i18n/astro.h b/contrib/libs/icu/i18n/astro.h
index a246489005..93a2fa6953 100644
--- a/contrib/libs/icu/i18n/astro.h
+++ b/contrib/libs/icu/i18n/astro.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/************************************************************************
* Copyright (C) 1996-2008, International Business Machines Corporation *
diff --git a/contrib/libs/icu/i18n/basictz.cpp b/contrib/libs/icu/i18n/basictz.cpp
index 54ee5a1a2b..43ed52a5b4 100644
--- a/contrib/libs/icu/i18n/basictz.cpp
+++ b/contrib/libs/icu/i18n/basictz.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/bocsu.cpp b/contrib/libs/icu/i18n/bocsu.cpp
index 861a76a042..efb7bcf57d 100644
--- a/contrib/libs/icu/i18n/bocsu.cpp
+++ b/contrib/libs/icu/i18n/bocsu.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -6,7 +6,7 @@
* Corporation and others. All Rights Reserved.
*******************************************************************************
* file name: bocsu.cpp
-* encoding: UTF-8
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
diff --git a/contrib/libs/icu/i18n/bocsu.h b/contrib/libs/icu/i18n/bocsu.h
index 631e29aa76..f7a552a0d7 100644
--- a/contrib/libs/icu/i18n/bocsu.h
+++ b/contrib/libs/icu/i18n/bocsu.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -6,7 +6,7 @@
* Corporation and others. All Rights Reserved.
*******************************************************************************
* file name: bocsu.h
-* encoding: UTF-8
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
@@ -144,14 +144,14 @@ U_NAMESPACE_END
* yields negative modulo results and quotients that are one more than
* what we need here.
*/
-#define NEGDIVMOD(n, d, m) UPRV_BLOCK_MACRO_BEGIN { \
+#define NEGDIVMOD(n, d, m) UPRV_BLOCK_MACRO_BEGIN { \
(m)=(n)%(d); \
(n)/=(d); \
if((m)<0) { \
--(n); \
(m)+=(d); \
} \
-} UPRV_BLOCK_MACRO_END
+} UPRV_BLOCK_MACRO_END
U_CFUNC UChar32
u_writeIdenticalLevelRun(UChar32 prev, const UChar *s, int32_t length, icu::ByteSink &sink);
diff --git a/contrib/libs/icu/i18n/brktrans.cpp b/contrib/libs/icu/i18n/brktrans.cpp
index 46b0e345da..d6b10c4778 100644
--- a/contrib/libs/icu/i18n/brktrans.cpp
+++ b/contrib/libs/icu/i18n/brktrans.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -10,8 +10,8 @@
**********************************************************************
*/
-#include <utility>
-
+#include <utility>
+
#include "unicode/utypes.h"
#if !UCONFIG_NO_TRANSLITERATION && !UCONFIG_NO_BREAK_ITERATION
@@ -64,7 +64,7 @@ BreakTransliterator::BreakTransliterator(const BreakTransliterator& o) :
/**
* Transliterator API.
*/
-BreakTransliterator* BreakTransliterator::clone() const {
+BreakTransliterator* BreakTransliterator::clone() const {
return new BreakTransliterator(*this);
}
@@ -81,8 +81,8 @@ void BreakTransliterator::handleTransliterate(Replaceable& text, UTransPosition&
{
Mutex m;
BreakTransliterator *nonConstThis = const_cast<BreakTransliterator *>(this);
- boundaries = std::move(nonConstThis->cachedBoundaries);
- bi = std::move(nonConstThis->cachedBI);
+ boundaries = std::move(nonConstThis->cachedBoundaries);
+ bi = std::move(nonConstThis->cachedBI);
}
if (bi.isNull()) {
bi.adoptInstead(BreakIterator::createWordInstance(Locale::getEnglish(), status));
@@ -147,10 +147,10 @@ void BreakTransliterator::handleTransliterate(Replaceable& text, UTransPosition&
Mutex m;
BreakTransliterator *nonConstThis = const_cast<BreakTransliterator *>(this);
if (nonConstThis->cachedBI.isNull()) {
- nonConstThis->cachedBI = std::move(bi);
+ nonConstThis->cachedBI = std::move(bi);
}
if (nonConstThis->cachedBoundaries.isNull()) {
- nonConstThis->cachedBoundaries = std::move(boundaries);
+ nonConstThis->cachedBoundaries = std::move(boundaries);
}
}
diff --git a/contrib/libs/icu/i18n/brktrans.h b/contrib/libs/icu/i18n/brktrans.h
index cb3def9e92..c129761d28 100644
--- a/contrib/libs/icu/i18n/brktrans.h
+++ b/contrib/libs/icu/i18n/brktrans.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -54,7 +54,7 @@ public:
* Transliterator API.
* @return A copy of the object.
*/
- virtual BreakTransliterator* clone() const;
+ virtual BreakTransliterator* clone() const;
virtual const UnicodeString &getInsertion() const;
diff --git a/contrib/libs/icu/i18n/buddhcal.cpp b/contrib/libs/icu/i18n/buddhcal.cpp
index 6083349ecd..df3b3112e9 100644
--- a/contrib/libs/icu/i18n/buddhcal.cpp
+++ b/contrib/libs/icu/i18n/buddhcal.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -53,7 +53,7 @@ BuddhistCalendar& BuddhistCalendar::operator= ( const BuddhistCalendar& right)
return *this;
}
-BuddhistCalendar* BuddhistCalendar::clone() const
+BuddhistCalendar* BuddhistCalendar::clone() const
{
return new BuddhistCalendar(*this);
}
@@ -133,7 +133,7 @@ void BuddhistCalendar::timeToFields(UDate theTime, UBool quick, UErrorCode& stat
*/
static UDate gSystemDefaultCenturyStart = DBL_MIN;
static int32_t gSystemDefaultCenturyStartYear = -1;
-static icu::UInitOnce gBCInitOnce = U_INITONCE_INITIALIZER;
+static icu::UInitOnce gBCInitOnce = U_INITONCE_INITIALIZER;
UBool BuddhistCalendar::haveDefaultCentury() const
diff --git a/contrib/libs/icu/i18n/buddhcal.h b/contrib/libs/icu/i18n/buddhcal.h
index 0ad0886df1..6e95e75924 100644
--- a/contrib/libs/icu/i18n/buddhcal.h
+++ b/contrib/libs/icu/i18n/buddhcal.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
********************************************************************************
@@ -94,7 +94,7 @@ public:
* @return return a polymorphic copy of this calendar.
* @internal
*/
- virtual BuddhistCalendar* clone() const;
+ virtual BuddhistCalendar* clone() const;
public:
/**
diff --git a/contrib/libs/icu/i18n/calendar.cpp b/contrib/libs/icu/i18n/calendar.cpp
index 981f09c574..bc299aa4c8 100644
--- a/contrib/libs/icu/i18n/calendar.cpp
+++ b/contrib/libs/icu/i18n/calendar.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -8,12 +8,12 @@
*
* File CALENDAR.CPP
*
-* Modification History:
+* Modification History:
*
* Date Name Description
* 02/03/97 clhuang Creation.
-* 04/22/97 aliu Cleaned up, fixed memory leak, made
-* setWeekCountData() more robust.
+* 04/22/97 aliu Cleaned up, fixed memory leak, made
+* setWeekCountData() more robust.
* Moved platform code to TPlatformUtilities.
* 05/01/97 aliu Made equals(), before(), after() arguments const.
* 05/20/97 aliu Changed logic of when to compute fields and time
@@ -26,7 +26,7 @@
*******************************************************************************
*/
-#include "utypeinfo.h" // for 'typeid' to work
+#include "utypeinfo.h" // for 'typeid' to work
#include "unicode/utypes.h"
@@ -80,7 +80,7 @@ static UBool calendar_cleanup(void) {
return TRUE;
}
U_CDECL_END
-#endif
+#endif
// ------------------------------------------
//
@@ -92,9 +92,9 @@ U_CDECL_END
#if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
-/**
- * fldName was removed as a duplicate implementation.
- * use udbg_ services instead,
+/**
+ * fldName was removed as a duplicate implementation.
+ * use udbg_ services instead,
* which depend on include files and library from ../tools/toolutil, the following circular link:
* CPPFLAGS+=-I$(top_srcdir)/tools/toolutil
* LIBS+=$(LIBICUTOOLUTIL)
@@ -122,7 +122,7 @@ void ucal_dump(const Calendar &cal) {
void Calendar::dump() const {
int i;
fprintf(stderr, "@calendar=%s, timeset=%c, fieldset=%c, allfields=%c, virtualset=%c, t=%.2f",
- getType(), fIsTimeSet?'y':'n', fAreFieldsSet?'y':'n', fAreAllFieldsSet?'y':'n',
+ getType(), fIsTimeSet?'y':'n', fAreFieldsSet?'y':'n', fAreAllFieldsSet?'y':'n',
fAreFieldsVirtuallySet?'y':'n',
fTime);
@@ -134,9 +134,9 @@ void Calendar::dump() const {
fprintf(stderr, " %25s: %-11ld", f, fFields[i]);
if(fStamp[i] == kUnset) {
fprintf(stderr, " (unset) ");
- } else if(fStamp[i] == kInternallySet) {
+ } else if(fStamp[i] == kInternallySet) {
fprintf(stderr, " (internally set) ");
- //} else if(fStamp[i] == kInternalDefault) {
+ //} else if(fStamp[i] == kInternalDefault) {
// fprintf(stderr, " (internal default) ");
} else {
fprintf(stderr, " %%%d ", fStamp[i]);
@@ -212,7 +212,7 @@ const SharedCalendar *LocaleCacheKey<SharedCalendar>::createObject(
const void * /*unusedCreationContext*/, UErrorCode &status) const {
Calendar *calendar = Calendar::makeInstance(fLoc, status);
if (U_FAILURE(status)) {
- return NULL;
+ return NULL;
}
SharedCalendar *shared = new SharedCalendar(calendar);
if (shared == NULL) {
@@ -233,9 +233,9 @@ static ECalType getCalendarType(const char *s) {
return CALTYPE_UNKNOWN;
}
-#if !UCONFIG_NO_SERVICE
-// Only used with service registration.
-static UBool isStandardSupportedKeyword(const char *keyword, UErrorCode& status) {
+#if !UCONFIG_NO_SERVICE
+// Only used with service registration.
+static UBool isStandardSupportedKeyword(const char *keyword, UErrorCode& status) {
if(U_FAILURE(status)) {
return FALSE;
}
@@ -243,7 +243,7 @@ static UBool isStandardSupportedKeyword(const char *keyword, UErrorCode& status)
return (calType != CALTYPE_UNKNOWN);
}
-// only used with service registration.
+// only used with service registration.
static void getCalendarKeyword(const UnicodeString &id, char *targetBuffer, int32_t targetBufferSize) {
UnicodeString calendarKeyword = UNICODE_STRING_SIMPLE("calendar=");
int32_t calKeyLen = calendarKeyword.length();
@@ -257,7 +257,7 @@ static void getCalendarKeyword(const UnicodeString &id, char *targetBuffer, int3
}
targetBuffer[keyLen] = 0;
}
-#endif
+#endif
static ECalType getCalendarTypeForLocale(const char *locid) {
UErrorCode status = U_ZERO_ERROR;
@@ -268,8 +268,8 @@ static ECalType getCalendarTypeForLocale(const char *locid) {
// canonicalize, so grandfathered variant will be transformed to keywords
// e.g ja_JP_TRADITIONAL -> ja_JP@calendar=japanese
- // NOTE: Since ICU-20187, ja_JP_TRADITIONAL no longer canonicalizes, and
- // the Gregorian calendar is returned instead.
+ // NOTE: Since ICU-20187, ja_JP_TRADITIONAL no longer canonicalizes, and
+ // the Gregorian calendar is returned instead.
int32_t canonicalLen = uloc_canonicalize(locid, canonicalName, sizeof(canonicalName) - 1, &status);
if (U_FAILURE(status)) {
return CALTYPE_GREGORIAN;
@@ -296,7 +296,7 @@ static ECalType getCalendarTypeForLocale(const char *locid) {
if (U_FAILURE(status)) {
return CALTYPE_GREGORIAN;
}
-
+
// Read preferred calendar values from supplementalData calendarPreference
UResourceBundle *rb = ures_openDirect(NULL, "supplementalData", &status);
ures_getByKey(rb, "calendarPreferenceData", rb, &status);
@@ -329,73 +329,73 @@ static ECalType getCalendarTypeForLocale(const char *locid) {
}
static Calendar *createStandardCalendar(ECalType calType, const Locale &loc, UErrorCode& status) {
- if (U_FAILURE(status)) {
- return nullptr;
- }
- LocalPointer<Calendar> cal;
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ LocalPointer<Calendar> cal;
switch (calType) {
case CALTYPE_GREGORIAN:
- cal.adoptInsteadAndCheckErrorCode(new GregorianCalendar(loc, status), status);
+ cal.adoptInsteadAndCheckErrorCode(new GregorianCalendar(loc, status), status);
break;
case CALTYPE_JAPANESE:
- cal.adoptInsteadAndCheckErrorCode(new JapaneseCalendar(loc, status), status);
+ cal.adoptInsteadAndCheckErrorCode(new JapaneseCalendar(loc, status), status);
break;
case CALTYPE_BUDDHIST:
- cal.adoptInsteadAndCheckErrorCode(new BuddhistCalendar(loc, status), status);
+ cal.adoptInsteadAndCheckErrorCode(new BuddhistCalendar(loc, status), status);
break;
case CALTYPE_ROC:
- cal.adoptInsteadAndCheckErrorCode(new TaiwanCalendar(loc, status), status);
+ cal.adoptInsteadAndCheckErrorCode(new TaiwanCalendar(loc, status), status);
break;
case CALTYPE_PERSIAN:
- cal.adoptInsteadAndCheckErrorCode(new PersianCalendar(loc, status), status);
+ cal.adoptInsteadAndCheckErrorCode(new PersianCalendar(loc, status), status);
break;
case CALTYPE_ISLAMIC_TBLA:
- cal.adoptInsteadAndCheckErrorCode(new IslamicCalendar(loc, status, IslamicCalendar::TBLA), status);
+ cal.adoptInsteadAndCheckErrorCode(new IslamicCalendar(loc, status, IslamicCalendar::TBLA), status);
break;
case CALTYPE_ISLAMIC_CIVIL:
- cal.adoptInsteadAndCheckErrorCode(new IslamicCalendar(loc, status, IslamicCalendar::CIVIL), status);
+ cal.adoptInsteadAndCheckErrorCode(new IslamicCalendar(loc, status, IslamicCalendar::CIVIL), status);
break;
case CALTYPE_ISLAMIC_RGSA:
// default any region specific not handled individually to islamic
case CALTYPE_ISLAMIC:
- cal.adoptInsteadAndCheckErrorCode(new IslamicCalendar(loc, status, IslamicCalendar::ASTRONOMICAL), status);
+ cal.adoptInsteadAndCheckErrorCode(new IslamicCalendar(loc, status, IslamicCalendar::ASTRONOMICAL), status);
break;
case CALTYPE_ISLAMIC_UMALQURA:
- cal.adoptInsteadAndCheckErrorCode(new IslamicCalendar(loc, status, IslamicCalendar::UMALQURA), status);
+ cal.adoptInsteadAndCheckErrorCode(new IslamicCalendar(loc, status, IslamicCalendar::UMALQURA), status);
break;
case CALTYPE_HEBREW:
- cal.adoptInsteadAndCheckErrorCode(new HebrewCalendar(loc, status), status);
+ cal.adoptInsteadAndCheckErrorCode(new HebrewCalendar(loc, status), status);
break;
case CALTYPE_CHINESE:
- cal.adoptInsteadAndCheckErrorCode(new ChineseCalendar(loc, status), status);
+ cal.adoptInsteadAndCheckErrorCode(new ChineseCalendar(loc, status), status);
break;
case CALTYPE_INDIAN:
- cal.adoptInsteadAndCheckErrorCode(new IndianCalendar(loc, status), status);
+ cal.adoptInsteadAndCheckErrorCode(new IndianCalendar(loc, status), status);
break;
case CALTYPE_COPTIC:
- cal.adoptInsteadAndCheckErrorCode(new CopticCalendar(loc, status), status);
+ cal.adoptInsteadAndCheckErrorCode(new CopticCalendar(loc, status), status);
break;
case CALTYPE_ETHIOPIC:
- cal.adoptInsteadAndCheckErrorCode(new EthiopicCalendar(loc, status, EthiopicCalendar::AMETE_MIHRET_ERA), status);
+ cal.adoptInsteadAndCheckErrorCode(new EthiopicCalendar(loc, status, EthiopicCalendar::AMETE_MIHRET_ERA), status);
break;
case CALTYPE_ETHIOPIC_AMETE_ALEM:
- cal.adoptInsteadAndCheckErrorCode(new EthiopicCalendar(loc, status, EthiopicCalendar::AMETE_ALEM_ERA), status);
+ cal.adoptInsteadAndCheckErrorCode(new EthiopicCalendar(loc, status, EthiopicCalendar::AMETE_ALEM_ERA), status);
break;
case CALTYPE_ISO8601:
- cal.adoptInsteadAndCheckErrorCode(new GregorianCalendar(loc, status), status);
- if (cal.isValid()) {
- cal->setFirstDayOfWeek(UCAL_MONDAY);
- cal->setMinimalDaysInFirstWeek(4);
- }
+ cal.adoptInsteadAndCheckErrorCode(new GregorianCalendar(loc, status), status);
+ if (cal.isValid()) {
+ cal->setFirstDayOfWeek(UCAL_MONDAY);
+ cal->setMinimalDaysInFirstWeek(4);
+ }
break;
case CALTYPE_DANGI:
- cal.adoptInsteadAndCheckErrorCode(new DangiCalendar(loc, status), status);
+ cal.adoptInsteadAndCheckErrorCode(new DangiCalendar(loc, status), status);
break;
default:
status = U_UNSUPPORTED_ERROR;
}
- return cal.orphan();
+ return cal.orphan();
}
@@ -404,7 +404,7 @@ static Calendar *createStandardCalendar(ECalType calType, const Locale &loc, UEr
// -------------------------------------
/**
-* a Calendar Factory which creates the "basic" calendar types, that is, those
+* a Calendar Factory which creates the "basic" calendar types, that is, those
* shipped with ICU.
*/
class BasicCalendarFactory : public LocaleKeyFactory {
@@ -418,7 +418,7 @@ public:
virtual ~BasicCalendarFactory();
protected:
- //virtual UBool isSupportedID( const UnicodeString& id, UErrorCode& status) const {
+ //virtual UBool isSupportedID( const UnicodeString& id, UErrorCode& status) const {
// if(U_FAILURE(status)) {
// return FALSE;
// }
@@ -476,7 +476,7 @@ protected:
BasicCalendarFactory::~BasicCalendarFactory() {}
-/**
+/**
* A factory which looks up the DefaultCalendar resource to determine which class of calendar to use
*/
@@ -520,7 +520,7 @@ public:
virtual UObject* cloneInstance(UObject* instance) const {
UnicodeString *s = dynamic_cast<UnicodeString *>(instance);
if(s != NULL) {
- return s->clone();
+ return s->clone();
} else {
#ifdef U_DEBUG_CALSVC_F
UErrorCode status2 = U_ZERO_ERROR;
@@ -543,10 +543,10 @@ public:
fprintf(stderr, "CalSvc:handleDefault for currentLoc %s, canloc %s\n", (const char*)loc.getName(), (const char*)loc2.getName());
#endif
Calendar *nc = new GregorianCalendar(loc, status);
- if (nc == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return nc;
- }
+ if (nc == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nc;
+ }
#ifdef U_DEBUG_CALSVC
UErrorCode status2 = U_ZERO_ERROR;
@@ -587,7 +587,7 @@ initCalendarService(UErrorCode &status)
fprintf(stderr, "Registering classes..\n");
#endif
- // Register all basic instances.
+ // Register all basic instances.
gService->registerFactory(new BasicCalendarFactory(),status);
#ifdef U_DEBUG_CALSVC
@@ -603,7 +603,7 @@ initCalendarService(UErrorCode &status)
}
}
-static ICULocaleService*
+static ICULocaleService*
getCalendarService(UErrorCode &status)
{
umtx_initOnce(gServiceInitOnce, &initCalendarService, status);
@@ -719,8 +719,8 @@ fZone(NULL),
fRepeatedWallTime(UCAL_WALLTIME_LAST),
fSkippedWallTime(UCAL_WALLTIME_LAST)
{
- validLocale[0] = 0;
- actualLocale[0] = 0;
+ validLocale[0] = 0;
+ actualLocale[0] = 0;
clear();
if (U_FAILURE(success)) {
return;
@@ -747,10 +747,10 @@ fZone(NULL),
fRepeatedWallTime(UCAL_WALLTIME_LAST),
fSkippedWallTime(UCAL_WALLTIME_LAST)
{
- validLocale[0] = 0;
- actualLocale[0] = 0;
+ validLocale[0] = 0;
+ actualLocale[0] = 0;
if (U_FAILURE(success)) {
- delete zone;
+ delete zone;
return;
}
if(zone == 0) {
@@ -762,7 +762,7 @@ fSkippedWallTime(UCAL_WALLTIME_LAST)
return;
}
- clear();
+ clear();
fZone = zone;
setWeekData(aLocale, NULL, success);
}
@@ -782,8 +782,8 @@ fZone(NULL),
fRepeatedWallTime(UCAL_WALLTIME_LAST),
fSkippedWallTime(UCAL_WALLTIME_LAST)
{
- validLocale[0] = 0;
- actualLocale[0] = 0;
+ validLocale[0] = 0;
+ actualLocale[0] = 0;
if (U_FAILURE(success)) {
return;
}
@@ -840,10 +840,10 @@ Calendar::operator=(const Calendar &right)
fWeekendCease = right.fWeekendCease;
fWeekendCeaseMillis = right.fWeekendCeaseMillis;
fNextStamp = right.fNextStamp;
- uprv_strncpy(validLocale, right.validLocale, sizeof(validLocale));
- uprv_strncpy(actualLocale, right.actualLocale, sizeof(actualLocale));
- validLocale[sizeof(validLocale)-1] = 0;
- actualLocale[sizeof(validLocale)-1] = 0;
+ uprv_strncpy(validLocale, right.validLocale, sizeof(validLocale));
+ uprv_strncpy(actualLocale, right.actualLocale, sizeof(actualLocale));
+ validLocale[sizeof(validLocale)-1] = 0;
+ actualLocale[sizeof(validLocale)-1] = 0;
}
return *this;
@@ -873,7 +873,7 @@ Calendar::createInstance(const Locale& aLocale, UErrorCode& success)
return createInstance(TimeZone::createDefault(), aLocale, success);
}
-// ------------------------------------- Adopting
+// ------------------------------------- Adopting
// Note: this is the bottleneck that actually calls the service routines.
@@ -926,7 +926,7 @@ Calendar::makeInstance(const Locale& aLocale, UErrorCode& success) {
c = (Calendar*)getCalendarService(success)->get(l, LocaleKey::KIND_ANY, &actualLoc2, success);
if(U_FAILURE(success) || !c) {
- if(U_SUCCESS(success)) {
+ if(U_SUCCESS(success)) {
success = U_INTERNAL_PROGRAM_ERROR; // Propagate some err
}
return NULL;
@@ -934,7 +934,7 @@ Calendar::makeInstance(const Locale& aLocale, UErrorCode& success) {
str = dynamic_cast<const UnicodeString*>(c);
if(str != NULL) {
- // recursed! Second lookup returned a UnicodeString.
+ // recursed! Second lookup returned a UnicodeString.
// Perhaps DefaultCalendar{} was set to another locale.
#ifdef U_DEBUG_CALSVC
char tmp[200];
@@ -958,7 +958,7 @@ Calendar::makeInstance(const Locale& aLocale, UErrorCode& success) {
#endif
c->setWeekData(aLocale, c->getType(), success); // set the correct locale (this was an indirected calendar)
- char keyword[ULOC_FULLNAME_CAPACITY] = "";
+ char keyword[ULOC_FULLNAME_CAPACITY] = "";
UErrorCode tmpStatus = U_ZERO_ERROR;
l.getKeywordValue("calendar", keyword, ULOC_FULLNAME_CAPACITY, tmpStatus);
if (U_SUCCESS(tmpStatus) && uprv_strcmp(keyword, "iso8601") == 0) {
@@ -1008,7 +1008,7 @@ Calendar::createInstance(const TimeZone& zone, const Locale& aLocale, UErrorCode
if(U_SUCCESS(success) && c) {
c->setTimeZone(zone);
}
- return c;
+ return c;
}
// -------------------------------------
@@ -1040,7 +1040,7 @@ Calendar::operator==(const Calendar& that) const
U_SUCCESS(status);
}
-UBool
+UBool
Calendar::isEquivalentTo(const Calendar& other) const
{
return typeid(*this) == typeid(other) &&
@@ -1105,11 +1105,11 @@ Calendar::getKeywordValuesForLocale(const char* key,
uenum_close(uenum);
return NULL;
}
- UStringEnumeration* ustringenum = new UStringEnumeration(uenum);
- if (ustringenum == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
- return ustringenum;
+ UStringEnumeration* ustringenum = new UStringEnumeration(uenum);
+ if (ustringenum == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return ustringenum;
}
// -------------------------------------
@@ -1126,13 +1126,13 @@ Calendar::getNow()
* Gets this Calendar's current time as a long.
* @return the current time as UTC milliseconds from the epoch.
*/
-double
+double
Calendar::getTimeInMillis(UErrorCode& status) const
{
- if(U_FAILURE(status))
+ if(U_FAILURE(status))
return 0.0;
- if ( ! fIsTimeSet)
+ if ( ! fIsTimeSet)
((Calendar*)this)->updateTime(status);
/* Test for buffer overflows */
@@ -1151,9 +1151,9 @@ Calendar::getTimeInMillis(UErrorCode& status) const
* when in lenient mode the out of range values are pinned to their respective min/max.
* @param date the new time in UTC milliseconds from the epoch.
*/
-void
+void
Calendar::setTimeInMillis( double millis, UErrorCode& status ) {
- if(U_FAILURE(status))
+ if(U_FAILURE(status))
return;
if (millis > MAX_MILLIS) {
@@ -1182,7 +1182,7 @@ Calendar::setTimeInMillis( double millis, UErrorCode& status ) {
fIsSet[i] = FALSE;
}
-
+
}
// -------------------------------------
@@ -1506,7 +1506,7 @@ void Calendar::computeFields(UErrorCode &ec)
double localMillis = internalGetTime();
int32_t rawOffset, dstOffset;
getTimeZone().getOffset(localMillis, FALSE, rawOffset, dstOffset, ec);
- localMillis += (rawOffset + dstOffset);
+ localMillis += (rawOffset + dstOffset);
// Mark fields as set. Do this before calling handleComputeFields().
uint32_t mask = //fInternalSetMask;
@@ -1515,7 +1515,7 @@ void Calendar::computeFields(UErrorCode &ec)
(1 << UCAL_MONTH) |
(1 << UCAL_DAY_OF_MONTH) | // = UCAL_DATE
(1 << UCAL_DAY_OF_YEAR) |
- (1 << UCAL_EXTENDED_YEAR);
+ (1 << UCAL_EXTENDED_YEAR);
for (int32_t i=0; i<UCAL_FIELD_COUNT; ++i) {
if ((mask & 1) == 0) {
@@ -1544,7 +1544,7 @@ void Calendar::computeFields(UErrorCode &ec)
#if defined (U_DEBUG_CAL)
//fprintf(stderr, "%s:%d- Hmm! Jules @ %d, as per %.0lf millis\n",
//__FILE__, __LINE__, fFields[UCAL_JULIAN_DAY], localMillis);
-#endif
+#endif
computeGregorianAndDOWFields(fFields[UCAL_JULIAN_DAY], ec);
@@ -1642,7 +1642,7 @@ void Calendar::computeGregorianFields(int32_t julianDay, UErrorCode & /* ec */)
* proleptic Gregorian calendar, which has no field larger than a year.
*/
void Calendar::computeWeekFields(UErrorCode &ec) {
- if(U_FAILURE(ec)) {
+ if(U_FAILURE(ec)) {
return;
}
int32_t eyear = fFields[UCAL_EXTENDED_YEAR];
@@ -1705,7 +1705,7 @@ void Calendar::computeWeekFields(UErrorCode &ec) {
fFields[UCAL_WEEK_OF_MONTH] = weekNumber(dayOfMonth, dayOfWeek);
fFields[UCAL_DAY_OF_WEEK_IN_MONTH] = (dayOfMonth-1) / 7 + 1;
#if defined (U_DEBUG_CAL)
- if(fFields[UCAL_DAY_OF_WEEK_IN_MONTH]==0) fprintf(stderr, "%s:%d: DOWIM %d on %g\n",
+ if(fFields[UCAL_DAY_OF_WEEK_IN_MONTH]==0) fprintf(stderr, "%s:%d: DOWIM %d on %g\n",
__FILE__, __LINE__,fFields[UCAL_DAY_OF_WEEK_IN_MONTH], fTime);
#endif
}
@@ -1750,7 +1750,7 @@ void Calendar::handleComputeFields(int32_t /* julianDay */, UErrorCode &/* statu
// -------------------------------------
-void Calendar::roll(EDateFields field, int32_t amount, UErrorCode& status)
+void Calendar::roll(EDateFields field, int32_t amount, UErrorCode& status)
{
roll((UCalendarDateFields)field, amount, status);
}
@@ -2088,7 +2088,7 @@ void Calendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& statu
default:
// Other fields cannot be rolled by this method
#if defined (U_DEBUG_CAL)
- fprintf(stderr, "%s:%d: ILLEGAL ARG because of roll on non-rollable field %s\n",
+ fprintf(stderr, "%s:%d: ILLEGAL ARG because of roll on non-rollable field %s\n",
__FILE__, __LINE__,fldName(field));
#endif
status = U_ILLEGAL_ARGUMENT_ERROR;
@@ -2279,7 +2279,7 @@ void Calendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status
}
}
}
- }
+ }
}
// -------------------------------------
@@ -2595,7 +2595,7 @@ Calendar::isWeekend(UDate date, UErrorCode &status) const
return FALSE;
}
// clone the calendar so we don't mess with the real one.
- Calendar *work = this->clone();
+ Calendar *work = this->clone();
if (work == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return FALSE;
@@ -2644,7 +2644,7 @@ Calendar::isWeekend(void) const
// ------------------------------------- limits
-int32_t
+int32_t
Calendar::getMinimum(EDateFields field) const {
return getLimit((UCalendarDateFields) field,UCAL_LIMIT_MINIMUM);
}
@@ -2695,7 +2695,7 @@ Calendar::getLeastMaximum(UCalendarDateFields field) const
}
// -------------------------------------
-int32_t
+int32_t
Calendar::getActualMinimum(EDateFields field, UErrorCode& status) const
{
return getActualMinimum((UCalendarDateFields) field, status);
@@ -2755,7 +2755,7 @@ Calendar::getActualMinimum(UCalendarDateFields field, UErrorCode& status) const
// clone the calendar so we don't mess with the real one, and set it to
// accept anything for the field values
- Calendar *work = this->clone();
+ Calendar *work = this->clone();
if (work == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return 0;
@@ -2771,7 +2771,7 @@ Calendar::getActualMinimum(UCalendarDateFields field, UErrorCode& status) const
work->set(field, fieldValue);
if (work->get(field, status) != fieldValue) {
break;
- }
+ }
else {
result = fieldValue;
fieldValue--;
@@ -2827,7 +2827,7 @@ void Calendar::validateField(UCalendarDateFields field, UErrorCode &status) {
case UCAL_DAY_OF_WEEK_IN_MONTH:
if (internalGet(field) == 0) {
#if defined (U_DEBUG_CAL)
- fprintf(stderr, "%s:%d: ILLEGAL ARG because DOW in month cannot be 0\n",
+ fprintf(stderr, "%s:%d: ILLEGAL ARG because DOW in month cannot be 0\n",
__FILE__, __LINE__);
#endif
status = U_ILLEGAL_ARGUMENT_ERROR; // "DAY_OF_WEEK_IN_MONTH cannot be zero"
@@ -2853,7 +2853,7 @@ void Calendar::validateField(UCalendarDateFields field, int32_t min, int32_t max
int32_t value = fFields[field];
if (value < min || value > max) {
#if defined (U_DEBUG_CAL)
- fprintf(stderr, "%s:%d: ILLEGAL ARG because of field %s out of range %d..%d at %d\n",
+ fprintf(stderr, "%s:%d: ILLEGAL ARG because of field %s out of range %d..%d at %d\n",
__FILE__, __LINE__,fldName(field),min,max,value);
#endif
status = U_ILLEGAL_ARGUMENT_ERROR;
@@ -2919,7 +2919,7 @@ linesInGroup:
}
const UFieldResolutionTable Calendar::kDatePrecedence[] =
-{
+{
{
{ UCAL_DAY_OF_MONTH, kResolveSTOP },
{ UCAL_WEEK_OF_YEAR, UCAL_DAY_OF_WEEK, kResolveSTOP },
@@ -2940,12 +2940,12 @@ const UFieldResolutionTable Calendar::kDatePrecedence[] =
{ kResolveRemap | UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_DAY_OF_WEEK, kResolveSTOP },
{ kResolveRemap | UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_DOW_LOCAL, kResolveSTOP },
{ kResolveSTOP }
- },
+ },
{{kResolveSTOP}}
};
-const UFieldResolutionTable Calendar::kDOWPrecedence[] =
+const UFieldResolutionTable Calendar::kDOWPrecedence[] =
{
{
{ UCAL_DAY_OF_WEEK,kResolveSTOP, kResolveSTOP },
@@ -2956,7 +2956,7 @@ const UFieldResolutionTable Calendar::kDOWPrecedence[] =
};
// precedence for calculating a year
-const UFieldResolutionTable Calendar::kYearPrecedence[] =
+const UFieldResolutionTable Calendar::kYearPrecedence[] =
{
{
{ UCAL_YEAR, kResolveSTOP },
@@ -2993,7 +2993,7 @@ void Calendar::computeTime(UErrorCode& status) {
// }
#endif
- double millisInDay;
+ double millisInDay;
// We only use MILLISECONDS_IN_DAY if it has been set by the user.
// This makes it possible for the caller to set the calendar to a
@@ -3113,10 +3113,10 @@ UBool Calendar::getImmediatePreviousZoneTransition(UDate base, UDate *transition
* reflects local zone wall time.
* @stable ICU 2.0
*/
-double Calendar::computeMillisInDay() {
+double Calendar::computeMillisInDay() {
// Do the time portion of the conversion.
- double millisInDay = 0;
+ double millisInDay = 0;
// Find the best set of fields specifying the time of day. There
// are only two possibilities here; the HOUR_OF_DAY or the
@@ -3158,7 +3158,7 @@ double Calendar::computeMillisInDay() {
* or range.
* @stable ICU 2.0
*/
-int32_t Calendar::computeZoneOffset(double millis, double millisInDay, UErrorCode &ec) {
+int32_t Calendar::computeZoneOffset(double millis, double millisInDay, UErrorCode &ec) {
int32_t rawOffset, dstOffset;
UDate wall = millis + millisInDay;
BasicTimeZone* btz = getBasicTimeZone();
@@ -3205,7 +3205,7 @@ int32_t Calendar::computeZoneOffset(double millis, double millisInDay, UErrorCod
return rawOffset + dstOffset;
}
-int32_t Calendar::computeJulianDay()
+int32_t Calendar::computeJulianDay()
{
// We want to see if any of the date fields is newer than the
// JULIAN_DAY. If not, then we use JULIAN_DAY. If so, then we do
@@ -3239,17 +3239,17 @@ int32_t Calendar::handleComputeJulianDay(UCalendarDateFields bestField) {
bestField == UCAL_DAY_OF_WEEK_IN_MONTH);
int32_t year;
- if (bestField == UCAL_WEEK_OF_YEAR && newerField(UCAL_YEAR_WOY, UCAL_YEAR) == UCAL_YEAR_WOY) {
- year = internalGet(UCAL_YEAR_WOY);
+ if (bestField == UCAL_WEEK_OF_YEAR && newerField(UCAL_YEAR_WOY, UCAL_YEAR) == UCAL_YEAR_WOY) {
+ year = internalGet(UCAL_YEAR_WOY);
} else {
year = handleGetExtendedYear();
}
- internalSet(UCAL_EXTENDED_YEAR, year);
-
-#if defined (U_DEBUG_CAL)
+ internalSet(UCAL_EXTENDED_YEAR, year);
+
+#if defined (U_DEBUG_CAL)
fprintf(stderr, "%s:%d: bestField= %s - y=%d\n", __FILE__, __LINE__, fldName(bestField), year);
-#endif
+#endif
// Get the Julian day of the day BEFORE the start of this year.
// If useMonth is true, get the day before the start of the month.
@@ -3331,9 +3331,9 @@ int32_t Calendar::handleComputeJulianDay(UCalendarDateFields bestField) {
date += ((monthLength - date) / 7 + dim + 1) * 7;
}
} else {
-#if defined (U_DEBUG_CAL)
+#if defined (U_DEBUG_CAL)
fprintf(stderr, "%s:%d - bf= %s\n", __FILE__, __LINE__, fldName(bestField));
-#endif
+#endif
if(bestField == UCAL_WEEK_OF_YEAR) { // ------------------------------------- WOY -------------
if(!isSet(UCAL_YEAR_WOY) || // YWOY not set at all or
@@ -3344,30 +3344,30 @@ int32_t Calendar::handleComputeJulianDay(UCalendarDateFields bestField) {
int32_t woy = internalGet(bestField);
int32_t nextJulianDay = handleComputeMonthStart(year+1, 0, FALSE); // jd of day before jan 1
- int32_t nextFirst = julianDayToDayOfWeek(nextJulianDay + 1) - firstDayOfWeek;
+ int32_t nextFirst = julianDayToDayOfWeek(nextJulianDay + 1) - firstDayOfWeek;
if (nextFirst < 0) { // 0..6 ldow of Jan 1
nextFirst += 7;
}
if(woy==1) { // FIRST WEEK ---------------------------------
-#if defined (U_DEBUG_CAL)
- fprintf(stderr, "%s:%d - woy=%d, yp=%d, nj(%d)=%d, nf=%d", __FILE__, __LINE__,
- internalGet(bestField), resolveFields(kYearPrecedence), year+1,
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d - woy=%d, yp=%d, nj(%d)=%d, nf=%d", __FILE__, __LINE__,
+ internalGet(bestField), resolveFields(kYearPrecedence), year+1,
nextJulianDay, nextFirst);
fprintf(stderr, " next: %d DFW, min=%d \n", (7-nextFirst), getMinimalDaysInFirstWeek() );
-#endif
+#endif
// nextFirst is now the localized DOW of Jan 1 of y-woy+1
if((nextFirst > 0) && // Jan 1 starts on FDOW
(7-nextFirst) >= getMinimalDaysInFirstWeek()) // or enough days in the week
{
// Jan 1 of (yearWoy+1) is in yearWoy+1 - recalculate JD to next year
-#if defined (U_DEBUG_CAL)
- fprintf(stderr, "%s:%d - was going to move JD from %d to %d [d%d]\n", __FILE__, __LINE__,
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d - was going to move JD from %d to %d [d%d]\n", __FILE__, __LINE__,
julianDay, nextJulianDay, (nextJulianDay-julianDay));
-#endif
+#endif
julianDay = nextJulianDay;
// recalculate 'first' [0-based local dow of jan 1]
@@ -3378,7 +3378,7 @@ int32_t Calendar::handleComputeJulianDay(UCalendarDateFields bestField) {
// recalculate date.
date = 1 - first + dowLocal;
}
- } else if(woy>=getLeastMaximum(bestField)) {
+ } else if(woy>=getLeastMaximum(bestField)) {
// could be in the last week- find out if this JD would overstep
int32_t testDate = date;
if ((7 - first) < getMinimalDaysInFirstWeek()) {
@@ -3388,7 +3388,7 @@ int32_t Calendar::handleComputeJulianDay(UCalendarDateFields bestField) {
// Now adjust for the week number.
testDate += 7 * (woy - 1);
-#if defined (U_DEBUG_CAL)
+#if defined (U_DEBUG_CAL)
fprintf(stderr, "%s:%d - y=%d, y-1=%d doy%d, njd%d (C.F. %d)\n",
__FILE__, __LINE__, year, year-1, testDate, julianDay+testDate, nextJulianDay);
#endif
@@ -3402,7 +3402,7 @@ int32_t Calendar::handleComputeJulianDay(UCalendarDateFields bestField) {
}
date = 1 - first + dowLocal;
-#if defined (U_DEBUG_CAL)
+#if defined (U_DEBUG_CAL)
fprintf(stderr, "%s:%d - date now %d, jd%d, ywoy%d\n",
__FILE__, __LINE__, date, julianDay, year-1);
#endif
@@ -3427,13 +3427,13 @@ int32_t Calendar::handleComputeJulianDay(UCalendarDateFields bestField) {
}
int32_t
-Calendar::getDefaultMonthInYear(int32_t /*eyear*/)
+Calendar::getDefaultMonthInYear(int32_t /*eyear*/)
{
return 0;
}
int32_t
-Calendar::getDefaultDayInMonth(int32_t /*eyear*/, int32_t /*month*/)
+Calendar::getDefaultDayInMonth(int32_t /*eyear*/, int32_t /*month*/)
{
return 1;
}
@@ -3463,13 +3463,13 @@ int32_t Calendar::getLocalDOW()
int32_t Calendar::handleGetExtendedYearFromWeekFields(int32_t yearWoy, int32_t woy)
{
- // We have UCAL_YEAR_WOY and UCAL_WEEK_OF_YEAR - from those, determine
+ // We have UCAL_YEAR_WOY and UCAL_WEEK_OF_YEAR - from those, determine
// what year we fall in, so that other code can set it properly.
// (code borrowed from computeWeekFields and handleComputeJulianDay)
//return yearWoy;
// First, we need a reliable DOW.
- UCalendarDateFields bestField = resolveFields(kDatePrecedence); // !! Note: if subclasses have a different table, they should override handleGetExtendedYearFromWeekFields
+ UCalendarDateFields bestField = resolveFields(kDatePrecedence); // !! Note: if subclasses have a different table, they should override handleGetExtendedYearFromWeekFields
// Now, a local DOW
int32_t dowLocal = getLocalDOW(); // 0..6
@@ -3502,9 +3502,9 @@ int32_t Calendar::handleGetExtendedYearFromWeekFields(int32_t yearWoy, int32_t w
int32_t minDays = getMinimalDaysInFirstWeek();
UBool jan1InPrevYear = FALSE; // January 1st in the year of WOY is the 1st week? (i.e. first week is < minimal )
- //UBool nextJan1InPrevYear = FALSE; // January 1st of Year of WOY + 1 is in the first week?
+ //UBool nextJan1InPrevYear = FALSE; // January 1st of Year of WOY + 1 is in the first week?
- if((7 - first) < minDays) {
+ if((7 - first) < minDays) {
jan1InPrevYear = TRUE;
}
@@ -3527,8 +3527,8 @@ int32_t Calendar::handleGetExtendedYearFromWeekFields(int32_t yearWoy, int32_t w
return yearWoy; // in this year
}
}
- } else if(woy >= getLeastMaximum(bestField)) {
- // we _might_ be in the last week..
+ } else if(woy >= getLeastMaximum(bestField)) {
+ // we _might_ be in the last week..
int32_t jd = // Calculate JD of our target day:
jan1Start + // JD of Jan 1
(7-first) + // days in the first week (Jan 1.. )
@@ -3565,7 +3565,7 @@ int32_t Calendar::handleGetExtendedYearFromWeekFields(int32_t yearWoy, int32_t w
}
//(internalGet(UCAL_DATE) <= (7-first)) /* && in minDow */ ) {
- //within 1st week and in this month..
+ //within 1st week and in this month..
//return yearWoy+1;
return yearWoy;
@@ -3698,7 +3698,7 @@ void Calendar::prepareGetActual(UCalendarDateFields field, UBool isMinimum, UErr
dow += 7;
}
}
-#if defined (U_DEBUG_CAL)
+#if defined (U_DEBUG_CAL)
fprintf(stderr, "prepareGetActualHelper(WOM/WOY) - dow=%d\n", dow);
#endif
set(UCAL_DAY_OF_WEEK, dow);
@@ -3714,7 +3714,7 @@ void Calendar::prepareGetActual(UCalendarDateFields field, UBool isMinimum, UErr
int32_t Calendar::getActualHelper(UCalendarDateFields field, int32_t startValue, int32_t endValue, UErrorCode &status) const
{
-#if defined (U_DEBUG_CAL)
+#if defined (U_DEBUG_CAL)
fprintf(stderr, "getActualHelper(%d,%d .. %d, %s)\n", field, startValue, endValue, u_errorName(status));
#endif
if (startValue == endValue) {
@@ -3750,7 +3750,7 @@ int32_t Calendar::getActualHelper(UCalendarDateFields field, int32_t startValue,
int32_t result = startValue;
if ((work->get(field, status) != startValue
&& field != UCAL_WEEK_OF_MONTH && delta > 0 ) || U_FAILURE(status)) {
-#if defined (U_DEBUG_CAL)
+#if defined (U_DEBUG_CAL)
fprintf(stderr, "getActualHelper(fld %d) - got %d (not %d) - %s\n", field, work->get(field,status), startValue, u_errorName(status));
#endif
} else {
@@ -3767,7 +3767,7 @@ int32_t Calendar::getActualHelper(UCalendarDateFields field, int32_t startValue,
} while (startValue != endValue);
}
delete work;
-#if defined (U_DEBUG_CAL)
+#if defined (U_DEBUG_CAL)
fprintf(stderr, "getActualHelper(%d) = %d\n", field, result);
#endif
return result;
@@ -3794,27 +3794,27 @@ Calendar::setWeekData(const Locale& desiredLocale, const char *type, UErrorCode&
// Since week and weekend data is territory based instead of language based,
// we may need to tweak the locale that we are using to try to get the appropriate
// values, using the following logic:
- // 1). If the locale has a language but no territory, use the territory as defined by
+ // 1). If the locale has a language but no territory, use the territory as defined by
// the likely subtags.
// 2). If the locale has a script designation then we ignore it,
// then remove it ( i.e. "en_Latn_US" becomes "en_US" )
-
+
UErrorCode myStatus = U_ZERO_ERROR;
- Locale min(desiredLocale);
- min.minimizeSubtags(myStatus);
+ Locale min(desiredLocale);
+ min.minimizeSubtags(myStatus);
Locale useLocale;
- if ( uprv_strlen(desiredLocale.getCountry()) == 0 ||
+ if ( uprv_strlen(desiredLocale.getCountry()) == 0 ||
(uprv_strlen(desiredLocale.getScript()) > 0 && uprv_strlen(min.getScript()) == 0) ) {
myStatus = U_ZERO_ERROR;
- Locale max(desiredLocale);
- max.addLikelySubtags(myStatus);
+ Locale max(desiredLocale);
+ max.addLikelySubtags(myStatus);
useLocale = Locale(max.getLanguage(),max.getCountry());
} else {
- useLocale = desiredLocale;
+ useLocale = desiredLocale;
}
-
- /* The code here is somewhat of a hack, since week data and weekend data aren't really tied to
+
+ /* The code here is somewhat of a hack, since week data and weekend data aren't really tied to
a specific calendar, they aren't truly locale data. But this is the only place where valid and
actual locale can be set, so we take a shot at it here by loading a representative resource
from the calendar data. The code used to use the dateTimeElements resource to get first day
@@ -3890,8 +3890,8 @@ Calendar::setWeekData(const Locale& desiredLocale, const char *type, UErrorCode&
* and areFieldsSet. Callers should check isTimeSet and only
* call this method if isTimeSet is false.
*/
-void
-Calendar::updateTime(UErrorCode& status)
+void
+Calendar::updateTime(UErrorCode& status)
{
computeTime(status);
if(U_FAILURE(status))
@@ -3900,14 +3900,14 @@ Calendar::updateTime(UErrorCode& status)
// If we are lenient, we need to recompute the fields to normalize
// the values. Also, if we haven't set all the fields yet (i.e.,
// in a newly-created object), we need to fill in the fields. [LIU]
- if (isLenient() || ! fAreAllFieldsSet)
+ if (isLenient() || ! fAreAllFieldsSet)
fAreFieldsSet = FALSE;
fIsTimeSet = TRUE;
fAreFieldsVirtuallySet = FALSE;
}
-Locale
+Locale
Calendar::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
U_LOCALE_BASED(locBased, *this);
return locBased.getLocale(type, status);
diff --git a/contrib/libs/icu/i18n/casetrn.cpp b/contrib/libs/icu/i18n/casetrn.cpp
index bb650f8fa2..a8f175e69a 100644
--- a/contrib/libs/icu/i18n/casetrn.cpp
+++ b/contrib/libs/icu/i18n/casetrn.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -8,7 +8,7 @@
*
*******************************************************************************
* file name: casetrn.cpp
-* encoding: UTF-8
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
@@ -109,7 +109,7 @@ CaseMapTransliterator::~CaseMapTransliterator() {
*/
CaseMapTransliterator::CaseMapTransliterator(const CaseMapTransliterator& o) :
Transliterator(o),
- fMap(o.fMap)
+ fMap(o.fMap)
{
}
@@ -125,7 +125,7 @@ CaseMapTransliterator::CaseMapTransliterator(const CaseMapTransliterator& o) :
/**
* Transliterator API.
*/
-/*CaseMapTransliterator* CaseMapTransliterator::clone() const {
+/*CaseMapTransliterator* CaseMapTransliterator::clone() const {
return new CaseMapTransliterator(*this);
}*/
@@ -149,14 +149,14 @@ void CaseMapTransliterator::handleTransliterate(Replaceable& text,
UnicodeString tmp;
const UChar *s;
UChar32 c;
- int32_t textPos, delta, result;
+ int32_t textPos, delta, result;
for(textPos=offsets.start; textPos<offsets.limit;) {
csc.cpStart=textPos;
c=text.char32At(textPos);
csc.cpLimit=textPos+=U16_LENGTH(c);
- result=fMap(c, utrans_rep_caseContextIterator, &csc, &s, UCASE_LOC_ROOT);
+ result=fMap(c, utrans_rep_caseContextIterator, &csc, &s, UCASE_LOC_ROOT);
if(csc.b1 && isIncremental) {
// fMap() tried to look beyond the context limit
diff --git a/contrib/libs/icu/i18n/casetrn.h b/contrib/libs/icu/i18n/casetrn.h
index 2ec3e736de..72dbe3978f 100644
--- a/contrib/libs/icu/i18n/casetrn.h
+++ b/contrib/libs/icu/i18n/casetrn.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -8,7 +8,7 @@
*
*******************************************************************************
* file name: casetrn.h
-* encoding: UTF-8
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
@@ -58,7 +58,7 @@ public:
* Transliterator API.
* @return a copy of the object.
*/
- virtual CaseMapTransliterator* clone() const = 0;
+ virtual CaseMapTransliterator* clone() const = 0;
/**
* ICU "poor man's RTTI", returns a UClassID for the actual class.
diff --git a/contrib/libs/icu/i18n/cecal.cpp b/contrib/libs/icu/i18n/cecal.cpp
index 00faa8ac07..890601ae08 100644
--- a/contrib/libs/icu/i18n/cecal.cpp
+++ b/contrib/libs/icu/i18n/cecal.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/cecal.h b/contrib/libs/icu/i18n/cecal.h
index c380f0bea3..e3f261fc4b 100644
--- a/contrib/libs/icu/i18n/cecal.h
+++ b/contrib/libs/icu/i18n/cecal.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/chnsecal.cpp b/contrib/libs/icu/i18n/chnsecal.cpp
index 4c03812715..c4af947781 100644
--- a/contrib/libs/icu/i18n/chnsecal.cpp
+++ b/contrib/libs/icu/i18n/chnsecal.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
@@ -51,7 +51,7 @@ static void debug_chnsecal_msg(const char *pat, ...)
// --- The cache --
-static icu::UMutex astroLock;
+static icu::UMutex astroLock;
static icu::CalendarAstronomer *gChineseCalendarAstro = NULL;
// Lazy Creation & Access synchronized by class CalendarCache with a mutex.
@@ -118,7 +118,7 @@ U_NAMESPACE_BEGIN
//-------------------------------------------------------------------------
-ChineseCalendar* ChineseCalendar::clone() const {
+ChineseCalendar* ChineseCalendar::clone() const {
return new ChineseCalendar(*this);
}
diff --git a/contrib/libs/icu/i18n/chnsecal.h b/contrib/libs/icu/i18n/chnsecal.h
index a0c21b6b5c..3b2de29b8b 100644
--- a/contrib/libs/icu/i18n/chnsecal.h
+++ b/contrib/libs/icu/i18n/chnsecal.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*****************************************************************************
@@ -144,7 +144,7 @@ class U_I18N_API ChineseCalendar : public Calendar {
virtual ~ChineseCalendar();
// clone
- virtual ChineseCalendar* clone() const;
+ virtual ChineseCalendar* clone() const;
private:
diff --git a/contrib/libs/icu/i18n/choicfmt.cpp b/contrib/libs/icu/i18n/choicfmt.cpp
index 7e26bb7a1f..9b42231961 100644
--- a/contrib/libs/icu/i18n/choicfmt.cpp
+++ b/contrib/libs/icu/i18n/choicfmt.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -563,7 +563,7 @@ ChoiceFormat::matchStringUntilLimitPart(
// -------------------------------------
-ChoiceFormat*
+ChoiceFormat*
ChoiceFormat::clone() const
{
ChoiceFormat *aCopy = new ChoiceFormat(*this);
diff --git a/contrib/libs/icu/i18n/coleitr.cpp b/contrib/libs/icu/i18n/coleitr.cpp
index 64d3ab4d2b..e8f714ec3a 100644
--- a/contrib/libs/icu/i18n/coleitr.cpp
+++ b/contrib/libs/icu/i18n/coleitr.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -29,7 +29,7 @@
#if !UCONFIG_NO_COLLATION
-#include "unicode/chariter.h"
+#include "unicode/chariter.h"
#include "unicode/coleitr.h"
#include "unicode/tblcoll.h"
#include "unicode/ustring.h"
diff --git a/contrib/libs/icu/i18n/coll.cpp b/contrib/libs/icu/i18n/coll.cpp
index 7b87b41dff..2eb219f698 100644
--- a/contrib/libs/icu/i18n/coll.cpp
+++ b/contrib/libs/icu/i18n/coll.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
@@ -63,11 +63,11 @@
static icu::Locale* availableLocaleList = NULL;
static int32_t availableLocaleListCount;
-#if !UCONFIG_NO_SERVICE
+#if !UCONFIG_NO_SERVICE
static icu::ICULocaleService* gService = NULL;
static icu::UInitOnce gServiceInitOnce = U_INITONCE_INITIALIZER;
-#endif
-static icu::UInitOnce gAvailableLocaleListInitOnce = U_INITONCE_INITIALIZER;
+#endif
+static icu::UInitOnce gAvailableLocaleListInitOnce = U_INITONCE_INITIALIZER;
/**
* Release all static memory held by collator.
@@ -226,21 +226,21 @@ initAvailableLocaleList(UErrorCode &status) {
U_ASSERT(availableLocaleList == NULL);
// for now, there is a hardcoded list, so just walk through that list and set it up.
UResourceBundle *index = NULL;
- StackUResourceBundle installed;
+ StackUResourceBundle installed;
int32_t i = 0;
index = ures_openDirect(U_ICUDATA_COLL, "res_index", &status);
- ures_getByKey(index, "InstalledLocales", installed.getAlias(), &status);
-
+ ures_getByKey(index, "InstalledLocales", installed.getAlias(), &status);
+
if(U_SUCCESS(status)) {
- availableLocaleListCount = ures_getSize(installed.getAlias());
+ availableLocaleListCount = ures_getSize(installed.getAlias());
availableLocaleList = new Locale[availableLocaleListCount];
if (availableLocaleList != NULL) {
- ures_resetIterator(installed.getAlias());
- while(ures_hasNext(installed.getAlias())) {
+ ures_resetIterator(installed.getAlias());
+ while(ures_hasNext(installed.getAlias())) {
const char *tempKey = NULL;
- ures_getNextString(installed.getAlias(), NULL, &tempKey, &status);
+ ures_getNextString(installed.getAlias(), NULL, &tempKey, &status);
availableLocaleList[i++] = Locale(tempKey);
}
}
@@ -446,14 +446,14 @@ Collator* U_EXPORT2 Collator::createInstance(const Locale& desiredLocale,
#endif
{
coll = makeInstance(desiredLocale, status);
- // Either returns NULL with U_FAILURE(status), or non-NULL with U_SUCCESS(status)
- }
- // The use of *coll in setAttributesFromKeywords can cause the NULL check to be
- // optimized out of the delete even though setAttributesFromKeywords returns
- // immediately if U_FAILURE(status), so we add a check here.
- if (U_FAILURE(status)) {
- return NULL;
- }
+ // Either returns NULL with U_FAILURE(status), or non-NULL with U_SUCCESS(status)
+ }
+ // The use of *coll in setAttributesFromKeywords can cause the NULL check to be
+ // optimized out of the delete even though setAttributesFromKeywords returns
+ // immediately if U_FAILURE(status), so we add a check here.
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
setAttributesFromKeywords(desiredLocale, *coll, status);
if (U_FAILURE(status)) {
delete coll;
@@ -991,8 +991,8 @@ Collator::internalCompareUTF8(const char *left, int32_t leftLength,
return UCOL_EQUAL;
}
return compareUTF8(
- StringPiece(left, (leftLength < 0) ? static_cast<int32_t>(uprv_strlen(left)) : leftLength),
- StringPiece(right, (rightLength < 0) ? static_cast<int32_t>(uprv_strlen(right)) : rightLength),
+ StringPiece(left, (leftLength < 0) ? static_cast<int32_t>(uprv_strlen(left)) : leftLength),
+ StringPiece(right, (rightLength < 0) ? static_cast<int32_t>(uprv_strlen(right)) : rightLength),
errorCode);
}
diff --git a/contrib/libs/icu/i18n/collation.cpp b/contrib/libs/icu/i18n/collation.cpp
index 14cb86576b..93faeee5d6 100644
--- a/contrib/libs/icu/i18n/collation.cpp
+++ b/contrib/libs/icu/i18n/collation.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collation.h b/contrib/libs/icu/i18n/collation.h
index e9256c9c12..a7d2326876 100644
--- a/contrib/libs/icu/i18n/collation.h
+++ b/contrib/libs/icu/i18n/collation.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collationbuilder.cpp b/contrib/libs/icu/i18n/collationbuilder.cpp
index 45ac6ddcd5..321dba031e 100644
--- a/contrib/libs/icu/i18n/collationbuilder.cpp
+++ b/contrib/libs/icu/i18n/collationbuilder.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -577,7 +577,7 @@ CollationBuilder::getSpecialResetPosition(const UnicodeString &str,
parserErrorReason = "LDML forbids tailoring to U+FFFF";
return 0;
default:
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
int32_t index = findOrInsertNodeForRootCE(ce, strength, errorCode);
diff --git a/contrib/libs/icu/i18n/collationbuilder.h b/contrib/libs/icu/i18n/collationbuilder.h
index 2f20050f93..7846b90d6a 100644
--- a/contrib/libs/icu/i18n/collationbuilder.h
+++ b/contrib/libs/icu/i18n/collationbuilder.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collationcompare.cpp b/contrib/libs/icu/i18n/collationcompare.cpp
index cbf32c9fe6..fda0f72a60 100644
--- a/contrib/libs/icu/i18n/collationcompare.cpp
+++ b/contrib/libs/icu/i18n/collationcompare.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collationcompare.h b/contrib/libs/icu/i18n/collationcompare.h
index 6ad2d06704..f9950666af 100644
--- a/contrib/libs/icu/i18n/collationcompare.h
+++ b/contrib/libs/icu/i18n/collationcompare.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collationdata.cpp b/contrib/libs/icu/i18n/collationdata.cpp
index 688770f8f6..addc134a73 100644
--- a/contrib/libs/icu/i18n/collationdata.cpp
+++ b/contrib/libs/icu/i18n/collationdata.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collationdata.h b/contrib/libs/icu/i18n/collationdata.h
index ab9b4c47ec..a4ff5035db 100644
--- a/contrib/libs/icu/i18n/collationdata.h
+++ b/contrib/libs/icu/i18n/collationdata.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collationdatabuilder.cpp b/contrib/libs/icu/i18n/collationdatabuilder.cpp
index 53361b86c7..a3b99360e4 100644
--- a/contrib/libs/icu/i18n/collationdatabuilder.cpp
+++ b/contrib/libs/icu/i18n/collationdatabuilder.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -852,7 +852,7 @@ CollationDataBuilder::copyFromBaseCE32(UChar32 c, uint32_t ce32, UBool withConte
ce32 = encodeOneCE(Collation::unassignedCEFromCodePoint(c), errorCode);
break;
default:
- UPRV_UNREACHABLE; // require ce32 == base->getFinalCE32(ce32)
+ UPRV_UNREACHABLE; // require ce32 == base->getFinalCE32(ce32)
}
return ce32;
}
diff --git a/contrib/libs/icu/i18n/collationdatabuilder.h b/contrib/libs/icu/i18n/collationdatabuilder.h
index fee444deee..380ac35f03 100644
--- a/contrib/libs/icu/i18n/collationdatabuilder.h
+++ b/contrib/libs/icu/i18n/collationdatabuilder.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collationdatareader.cpp b/contrib/libs/icu/i18n/collationdatareader.cpp
index 0eb1861343..9c1bfeeb92 100644
--- a/contrib/libs/icu/i18n/collationdatareader.cpp
+++ b/contrib/libs/icu/i18n/collationdatareader.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -419,8 +419,8 @@ CollationDataReader::read(const CollationTailoring *base, const uint8_t *inBytes
tailoring.data, ts, fastLatinPrimaries, UPRV_LENGTHOF(fastLatinPrimaries));
if(options == ts.options && ts.variableTop != 0 &&
reorderCodesLength == ts.reorderCodesLength &&
- (reorderCodesLength == 0 ||
- uprv_memcmp(reorderCodes, ts.reorderCodes, reorderCodesLength * 4) == 0) &&
+ (reorderCodesLength == 0 ||
+ uprv_memcmp(reorderCodes, ts.reorderCodes, reorderCodesLength * 4) == 0) &&
fastLatinOptions == ts.fastLatinOptions &&
(fastLatinOptions < 0 ||
uprv_memcmp(fastLatinPrimaries, ts.fastLatinPrimaries,
diff --git a/contrib/libs/icu/i18n/collationdatareader.h b/contrib/libs/icu/i18n/collationdatareader.h
index 44e69399e3..e5c6213910 100644
--- a/contrib/libs/icu/i18n/collationdatareader.h
+++ b/contrib/libs/icu/i18n/collationdatareader.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collationdatawriter.cpp b/contrib/libs/icu/i18n/collationdatawriter.cpp
index 823c8eb011..040cca3e3e 100644
--- a/contrib/libs/icu/i18n/collationdatawriter.cpp
+++ b/contrib/libs/icu/i18n/collationdatawriter.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -224,7 +224,7 @@ CollationDataWriter::write(UBool isBase, const UVersionInfo dataVersion,
int32_t totalSize = indexesLength * 4;
if(hasMappings && (isBase || data.jamoCE32s != baseData->jamoCE32s)) {
- indexes[CollationDataReader::IX_JAMO_CE32S_START] = static_cast<int32_t>(data.jamoCE32s - data.ce32s);
+ indexes[CollationDataReader::IX_JAMO_CE32S_START] = static_cast<int32_t>(data.jamoCE32s - data.ce32s);
} else {
indexes[CollationDataReader::IX_JAMO_CE32S_START] = -1;
}
diff --git a/contrib/libs/icu/i18n/collationdatawriter.h b/contrib/libs/icu/i18n/collationdatawriter.h
index 197cd5309f..3afdb6dd70 100644
--- a/contrib/libs/icu/i18n/collationdatawriter.h
+++ b/contrib/libs/icu/i18n/collationdatawriter.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collationfastlatin.cpp b/contrib/libs/icu/i18n/collationfastlatin.cpp
index b98b8457f4..0572c52676 100644
--- a/contrib/libs/icu/i18n/collationfastlatin.cpp
+++ b/contrib/libs/icu/i18n/collationfastlatin.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collationfastlatin.h b/contrib/libs/icu/i18n/collationfastlatin.h
index 4bac797409..8da1cecfac 100644
--- a/contrib/libs/icu/i18n/collationfastlatin.h
+++ b/contrib/libs/icu/i18n/collationfastlatin.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collationfastlatinbuilder.cpp b/contrib/libs/icu/i18n/collationfastlatinbuilder.cpp
index e5ba2f0e21..9205a562b0 100644
--- a/contrib/libs/icu/i18n/collationfastlatinbuilder.cpp
+++ b/contrib/libs/icu/i18n/collationfastlatinbuilder.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -607,7 +607,7 @@ CollationFastLatinBuilder::encodeContractions(UErrorCode &errorCode) {
}
UBool firstTriple = TRUE;
for(int32_t index = (int32_t)ce & 0x7fffffff;; index += 3) {
- int32_t x = static_cast<int32_t>(contractionCEs.elementAti(index));
+ int32_t x = static_cast<int32_t>(contractionCEs.elementAti(index));
if((uint32_t)x == CollationFastLatin::CONTR_CHAR_MASK && !firstTriple) { break; }
int64_t cce0 = contractionCEs.elementAti(index + 1);
int64_t cce1 = contractionCEs.elementAti(index + 2);
diff --git a/contrib/libs/icu/i18n/collationfastlatinbuilder.h b/contrib/libs/icu/i18n/collationfastlatinbuilder.h
index 8b63b86815..0f925a9beb 100644
--- a/contrib/libs/icu/i18n/collationfastlatinbuilder.h
+++ b/contrib/libs/icu/i18n/collationfastlatinbuilder.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collationfcd.cpp b/contrib/libs/icu/i18n/collationfcd.cpp
index 9f73ff3898..5daa4dddc5 100644
--- a/contrib/libs/icu/i18n/collationfcd.cpp
+++ b/contrib/libs/icu/i18n/collationfcd.cpp
@@ -1,14 +1,14 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
-//
-// Copyright (C) 1999-2016, International Business Machines
-// Corporation and others. All Rights Reserved.
-//
-// file name: collationfcd.cpp
-//
-// machine-generated by: icu/tools/unicode/c/genuca/genuca.cpp
-
+//
+// Copyright (C) 1999-2016, International Business Machines
+// Corporation and others. All Rights Reserved.
+//
+// file name: collationfcd.cpp
+//
+// machine-generated by: icu/tools/unicode/c/genuca/genuca.cpp
+
#include "unicode/utypes.h"
#if !UCONFIG_NO_COLLATION
@@ -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,0x19,
+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,0x1a,0,0,0x16,0x18,0,0,0x1b,0x18,0,0,0,0x1c,0,
-0,0x1d,0x1e,0,0,0x1d,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,0x1a,0,0,0x16,0x18,0,0,0x1b,0x18,0,0,0,0x1c,0,
+0,0x1d,0x1e,0,0,0x1d,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,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,0x2c,0,0,0x26,0x2d,0x2e,0,0x2f,0,0x30,
-0,0x31,0,0,0,0,0x32,0x33,0,0,0,0,0,0,1,0x34,
+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,0x2c,0,0,0x26,0x2d,0x2e,0,0x2f,0,0x30,
+0,0x31,0,0,0,0,0x32,0x33,0,0,0,0,0,0,1,0x34,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0x35,0x36,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x35,0x36,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0x37,0,0,0,0x38,0,0,0,1,
+0,0,0,0,0,0,0,0x37,0,0,0,0x38,0,0,0,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0x39,0,0,0x3a,0,0,0,0,0,0,0,0,0,0,0,
+0,0x39,0,0,0x3a,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,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,0x3b,0x3c,0,0,0x3d,0,0,0,0,0,0,0,0,
-0x23,0x3e,0,0,0,0,0x2d,0x3f,0,0x40,0x41,0,0,0x41,0x2c,0,
-0,0,0,0,0,0x42,0x43,0x44,0,0,0,0,0,0,0,0x18,
+0,0,0,0x3b,0x3c,0,0,0x3d,0,0,0,0,0,0,0,0,
+0x23,0x3e,0,0,0,0,0x2d,0x3f,0,0x40,0x41,0,0,0x41,0x2c,0,
+0,0,0,0,0,0x42,0x43,0x44,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,
-0x45,0x46,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x45,0x46,0,0,0,0,0,0,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,0x19,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[71]={
+const uint32_t CollationFCD::lcccBits[71]={
0,0xffffffff,0xffff7fff,0xffff,0xf8,0xfffe0000,0xbfffffff,0xb6,0x7ff0000,0xfffff800,0x10000,0x9fc00000,0x3d9f,0x20000,0xffff0000,0x7ff,
-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,0xbfff0000,1,0x10,0xff800,0xc00,
-0xc0040,0x800000,0xfff70000,0x31021fd,0xfbffffff,0x1fff0000,0x1ffe2,0x38000,0x80000000,0xfc00,0x6000000,0x3ff08000,0xc0000000,0x30000,0x1000,0x3ffff,
-0x3800,0x80000,0xc19d0000,2,0x400000,0xc0000fd,0x5108000
+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,0xbfff0000,1,0x10,0xff800,0xc00,
+0xc0040,0x800000,0xfff70000,0x31021fd,0xfbffffff,0x1fff0000,0x1ffe2,0x38000,0x80000000,0xfc00,0x6000000,0x3ff08000,0xc0000000,0x30000,0x1000,0x3ffff,
+0x3800,0x80000,0xc19d0000,2,0x400000,0xc0000fd,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,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,0x37,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,
+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,0x37,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,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,0x46,0,0,0x40,0x47,0x48,0,0x49,0,0x4a,
-0,0x4b,0,0,0,0,0x4c,0x4d,0,0,0,0,0,0,1,0x4e,
-1,1,1,1,0x4f,1,1,0x50,0x51,1,0x52,0x53,1,0x54,0x55,0x56,
-0,0,0,0,0,0,0x57,0x58,0,0x59,0,0,0x5a,0x5b,0x5c,0,
-0x5d,0x5e,0x5f,0x60,0x61,0x62,0,0x63,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,0x46,0,0,0x40,0x47,0x48,0,0x49,0,0x4a,
+0,0x4b,0,0,0,0,0x4c,0x4d,0,0,0,0,0,0,1,0x4e,
+1,1,1,1,0x4f,1,1,0x50,0x51,1,0x52,0x53,1,0x54,0x55,0x56,
+0,0,0,0,0,0,0x57,0x58,0,0x59,0,0,0x5a,0x5b,0x5c,0,
+0x5d,0x5e,0x5f,0x60,0x61,0x62,0,0x63,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0x64,0,0,0,0x65,0,0,0,1,
+0,0,0,0,0,0,0,0x64,0,0,0,0x65,0,0,0,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0x66,0x67,0x68,0x69,0x67,0x68,0x6a,0,0,0,0,0,0,0,0,
+0,0x66,0x67,0x68,0x69,0x67,0x68,0x6a,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,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,0x6b,0x6c,0,0,0x6d,0,0,0,0,0,0,0,0,
-0x3d,0x6e,0,0,0,0,0x47,0x6f,0,0x70,0x71,0,0,0x71,0x46,0,
-0,0,0,0,0,0x72,0x73,0x74,0,0,0,0,0,0,0,0x32,
+0,0,0,0x6b,0x6c,0,0,0x6d,0,0,0,0,0,0,0,0,
+0x3d,0x6e,0,0,0,0,0x47,0x6f,0,0x70,0x71,0,0,0x71,0x46,0,
+0,0,0,0,0,0x72,0x73,0x74,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,
-0x75,0x76,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x75,0x76,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,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,0x3f,0x77,0x78,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x3f,0x77,0x78,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[121]={
+const uint32_t CollationFCD::tcccBits[121]={
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,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,0xbfff0000,1,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,0x1000,0x3ffff,
-0x3800,0x80000,0xc19d0000,2,0x400000,0xc0000fd,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,0xbfff0000,1,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,0x1000,0x3ffff,
+0x3800,0x80000,0xc19d0000,2,0x400000,0xc0000fd,0x5108000,0x5f7ffc00,0x7fdb
};
U_NAMESPACE_END
diff --git a/contrib/libs/icu/i18n/collationfcd.h b/contrib/libs/icu/i18n/collationfcd.h
index ec7167d76b..206821d194 100644
--- a/contrib/libs/icu/i18n/collationfcd.h
+++ b/contrib/libs/icu/i18n/collationfcd.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collationiterator.cpp b/contrib/libs/icu/i18n/collationiterator.cpp
index 18ccf014f0..1a670d905f 100644
--- a/contrib/libs/icu/i18n/collationiterator.cpp
+++ b/contrib/libs/icu/i18n/collationiterator.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -872,7 +872,7 @@ CollationIterator::previousCE(UVector32 &offsets, UErrorCode &errorCode) {
// consistent with forward iteration.
while(offsets.size() <= ceBuffer.length) {
offsets.addElement(limitOffset, errorCode);
- }
+ }
}
return ceBuffer.get(--ceBuffer.length);
} else {
@@ -932,7 +932,7 @@ CollationIterator::previousCEUnsafe(UChar32 c, UVector32 &offsets, UErrorCode &e
offset = getOffset();
while(offsets.size() < ceBuffer.length) {
offsets.addElement(offset, errorCode);
- }
+ }
}
U_ASSERT(offsets.size() == ceBuffer.length);
// End offset corresponding to just after the unsafe-backwards segment.
diff --git a/contrib/libs/icu/i18n/collationiterator.h b/contrib/libs/icu/i18n/collationiterator.h
index 12e05b4482..aca46735b8 100644
--- a/contrib/libs/icu/i18n/collationiterator.h
+++ b/contrib/libs/icu/i18n/collationiterator.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -28,21 +28,21 @@ class SkippedState;
class UCharsTrie;
class UVector32;
-/* Large enough for CEs of most short strings. */
-#define CEBUFFER_INITIAL_CAPACITY 40
-
-// Export an explicit template instantiation of the MaybeStackArray that
-// is used as a data member of CEBuffer.
-//
-// 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<int64_t, CEBUFFER_INITIAL_CAPACITY>;
-#endif
-
+/* Large enough for CEs of most short strings. */
+#define CEBUFFER_INITIAL_CAPACITY 40
+
+// Export an explicit template instantiation of the MaybeStackArray that
+// is used as a data member of CEBuffer.
+//
+// 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<int64_t, CEBUFFER_INITIAL_CAPACITY>;
+#endif
+
/**
* Collation element iterator and abstract character iterator.
*
@@ -51,10 +51,10 @@ template class U_I18N_API MaybeStackArray<int64_t, CEBUFFER_INITIAL_CAPACITY>;
*/
class U_I18N_API CollationIterator : public UObject {
private:
- class U_I18N_API CEBuffer {
+ class U_I18N_API CEBuffer {
private:
/** Large enough for CEs of most short strings. */
- static const int32_t INITIAL_CAPACITY = CEBUFFER_INITIAL_CAPACITY;
+ static const int32_t INITIAL_CAPACITY = CEBUFFER_INITIAL_CAPACITY;
public:
CEBuffer() : length(0) {}
~CEBuffer();
diff --git a/contrib/libs/icu/i18n/collationkeys.cpp b/contrib/libs/icu/i18n/collationkeys.cpp
index b5c322fb44..2a5ec431b3 100644
--- a/contrib/libs/icu/i18n/collationkeys.cpp
+++ b/contrib/libs/icu/i18n/collationkeys.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -403,13 +403,13 @@ CollationKeys::writeSortKeyUpToQuaternary(CollationIterator &iter,
uint8_t *secs = secondaries.data();
int32_t last = secondaries.length() - 1;
if(secSegmentStart < last) {
- uint8_t *q = secs + secSegmentStart;
- uint8_t *r = secs + last;
+ uint8_t *q = secs + secSegmentStart;
+ uint8_t *r = secs + last;
do {
- uint8_t b = *q;
- *q++ = *r;
- *r-- = b;
- } while(q < r);
+ uint8_t b = *q;
+ *q++ = *r;
+ *r-- = b;
+ } while(q < r);
}
secondaries.appendByte(p == Collation::NO_CE_PRIMARY ?
Collation::LEVEL_SEPARATOR_BYTE : Collation::MERGE_SEPARATOR_BYTE);
diff --git a/contrib/libs/icu/i18n/collationkeys.h b/contrib/libs/icu/i18n/collationkeys.h
index 60d9e50c0d..dd0e157eda 100644
--- a/contrib/libs/icu/i18n/collationkeys.h
+++ b/contrib/libs/icu/i18n/collationkeys.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collationroot.cpp b/contrib/libs/icu/i18n/collationroot.cpp
index 71753bd6f4..c4afe6e8e4 100644
--- a/contrib/libs/icu/i18n/collationroot.cpp
+++ b/contrib/libs/icu/i18n/collationroot.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collationroot.h b/contrib/libs/icu/i18n/collationroot.h
index 8cd3046cdf..7e87f07b45 100644
--- a/contrib/libs/icu/i18n/collationroot.h
+++ b/contrib/libs/icu/i18n/collationroot.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collationrootelements.cpp b/contrib/libs/icu/i18n/collationrootelements.cpp
index 9b46d14144..995991429a 100644
--- a/contrib/libs/icu/i18n/collationrootelements.cpp
+++ b/contrib/libs/icu/i18n/collationrootelements.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collationrootelements.h b/contrib/libs/icu/i18n/collationrootelements.h
index 7836d8d83b..c3b30a51b9 100644
--- a/contrib/libs/icu/i18n/collationrootelements.h
+++ b/contrib/libs/icu/i18n/collationrootelements.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collationruleparser.cpp b/contrib/libs/icu/i18n/collationruleparser.cpp
index ade6ecb552..7c2014e7a8 100644
--- a/contrib/libs/icu/i18n/collationruleparser.cpp
+++ b/contrib/libs/icu/i18n/collationruleparser.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -622,11 +622,11 @@ CollationRuleParser::parseSetting(UErrorCode &errorCode) {
setParseError("expected language tag in [import langTag]", errorCode);
return;
}
- if(length == 0) {
+ if(length == 0) {
uprv_strcpy(baseID, "root");
- } else if(*baseID == '_') {
- uprv_memmove(baseID + 3, baseID, length + 1);
- uprv_memcpy(baseID, "und", 3);
+ } else if(*baseID == '_') {
+ uprv_memmove(baseID + 3, baseID, length + 1);
+ uprv_memcpy(baseID, "und", 3);
}
// @collation=type, or length=0 if not specified
char collationType[ULOC_KEYWORDS_CAPACITY];
diff --git a/contrib/libs/icu/i18n/collationruleparser.h b/contrib/libs/icu/i18n/collationruleparser.h
index e124881fcf..00907b6dad 100644
--- a/contrib/libs/icu/i18n/collationruleparser.h
+++ b/contrib/libs/icu/i18n/collationruleparser.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collationsets.cpp b/contrib/libs/icu/i18n/collationsets.cpp
index 09581416a8..008391f583 100644
--- a/contrib/libs/icu/i18n/collationsets.cpp
+++ b/contrib/libs/icu/i18n/collationsets.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collationsets.h b/contrib/libs/icu/i18n/collationsets.h
index aed41f7ac8..2862b5bda2 100644
--- a/contrib/libs/icu/i18n/collationsets.h
+++ b/contrib/libs/icu/i18n/collationsets.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collationsettings.cpp b/contrib/libs/icu/i18n/collationsettings.cpp
index 534e20df3e..1e2778fe72 100644
--- a/contrib/libs/icu/i18n/collationsettings.cpp
+++ b/contrib/libs/icu/i18n/collationsettings.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collationsettings.h b/contrib/libs/icu/i18n/collationsettings.h
index 83e775d443..5447dbfe3b 100644
--- a/contrib/libs/icu/i18n/collationsettings.h
+++ b/contrib/libs/icu/i18n/collationsettings.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collationtailoring.cpp b/contrib/libs/icu/i18n/collationtailoring.cpp
index 78a11fbb26..d2bf50ec44 100644
--- a/contrib/libs/icu/i18n/collationtailoring.cpp
+++ b/contrib/libs/icu/i18n/collationtailoring.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/collationtailoring.h b/contrib/libs/icu/i18n/collationtailoring.h
index e1bc34c7d7..a0ea0558f0 100644
--- a/contrib/libs/icu/i18n/collationtailoring.h
+++ b/contrib/libs/icu/i18n/collationtailoring.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -92,7 +92,7 @@ private:
CollationTailoring(const CollationTailoring &other);
};
-struct U_I18N_API CollationCacheEntry : public SharedObject {
+struct U_I18N_API CollationCacheEntry : public SharedObject {
CollationCacheEntry(const Locale &loc, const CollationTailoring *t)
: validLocale(loc), tailoring(t) {
if(t != NULL) {
diff --git a/contrib/libs/icu/i18n/collationweights.cpp b/contrib/libs/icu/i18n/collationweights.cpp
index 05458962c6..c185cdbcf3 100644
--- a/contrib/libs/icu/i18n/collationweights.cpp
+++ b/contrib/libs/icu/i18n/collationweights.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -8,7 +8,7 @@
*
*******************************************************************************
* file name: collationweights.cpp
-* encoding: UTF-8
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
@@ -527,7 +527,7 @@ CollationWeights::allocWeights(uint32_t lowerLimit, uint32_t upperLimit, int32_t
#ifdef UCOL_DEBUG
printf("lengthen the short ranges from %ld bytes to %ld and iterate\n", minLength, minLength+1);
#endif
- for(int32_t i=0; i<rangeCount && ranges[i].length==minLength; ++i) {
+ for(int32_t i=0; i<rangeCount && ranges[i].length==minLength; ++i) {
lengthenRange(ranges[i]);
}
}
diff --git a/contrib/libs/icu/i18n/collationweights.h b/contrib/libs/icu/i18n/collationweights.h
index b415882184..a9fd214675 100644
--- a/contrib/libs/icu/i18n/collationweights.h
+++ b/contrib/libs/icu/i18n/collationweights.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -8,7 +8,7 @@
*
*******************************************************************************
* file name: collationweights.h
-* encoding: UTF-8
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
diff --git a/contrib/libs/icu/i18n/collunsafe.h b/contrib/libs/icu/i18n/collunsafe.h
index 0767254a8a..b6dfc38245 100644
--- a/contrib/libs/icu/i18n/collunsafe.h
+++ b/contrib/libs/icu/i18n/collunsafe.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
// collunsafe.h
// Copyright (C) 2015-2016, International Business Machines Corporation and others.
diff --git a/contrib/libs/icu/i18n/compactdecimalformat.cpp b/contrib/libs/icu/i18n/compactdecimalformat.cpp
index a4c9dad25c..5abd218a87 100644
--- a/contrib/libs/icu/i18n/compactdecimalformat.cpp
+++ b/contrib/libs/icu/i18n/compactdecimalformat.cpp
@@ -1,75 +1,75 @@
-// © 2018 and later: Unicode, Inc. and others.
+// © 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
-
+// Allow implicit conversion from char16_t* to UnicodeString for this file:
+// Helpful in toString methods and elsewhere.
+#define UNISTR_FROM_STRING_EXPLICIT
+
#include "unicode/compactdecimalformat.h"
-#include "number_mapper.h"
-#include "number_decimfmtprops.h"
+#include "number_mapper.h"
+#include "number_decimfmtprops.h"
-using namespace icu;
+using namespace icu;
-UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CompactDecimalFormat)
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CompactDecimalFormat)
-CompactDecimalFormat*
-CompactDecimalFormat::createInstance(const Locale& inLocale, UNumberCompactStyle style,
- UErrorCode& status) {
- return new CompactDecimalFormat(inLocale, style, status);
+CompactDecimalFormat*
+CompactDecimalFormat::createInstance(const Locale& inLocale, UNumberCompactStyle style,
+ UErrorCode& status) {
+ return new CompactDecimalFormat(inLocale, style, 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);
+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);
}
-CompactDecimalFormat::CompactDecimalFormat(const CompactDecimalFormat& source) = default;
+CompactDecimalFormat::CompactDecimalFormat(const CompactDecimalFormat& source) = default;
-CompactDecimalFormat::~CompactDecimalFormat() = default;
+CompactDecimalFormat::~CompactDecimalFormat() = default;
-CompactDecimalFormat& CompactDecimalFormat::operator=(const CompactDecimalFormat& rhs) {
+CompactDecimalFormat& CompactDecimalFormat::operator=(const CompactDecimalFormat& rhs) {
DecimalFormat::operator=(rhs);
- return *this;
+ return *this;
}
-CompactDecimalFormat* CompactDecimalFormat::clone() const {
- return new CompactDecimalFormat(*this);
+CompactDecimalFormat* 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 nullptr;
+ const UnicodeString& /* text */,
+ ParsePosition& /* pos */) const {
+ return nullptr;
}
-#endif /* #if !UCONFIG_NO_FORMATTING */
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/coptccal.cpp b/contrib/libs/icu/i18n/coptccal.cpp
index 9c2b1ebbb7..2e46dd1e0d 100644
--- a/contrib/libs/icu/i18n/coptccal.cpp
+++ b/contrib/libs/icu/i18n/coptccal.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -40,7 +40,7 @@ CopticCalendar::~CopticCalendar()
{
}
-CopticCalendar*
+CopticCalendar*
CopticCalendar::clone() const
{
return new CopticCalendar(*this);
diff --git a/contrib/libs/icu/i18n/coptccal.h b/contrib/libs/icu/i18n/coptccal.h
index e9e812dbc7..eca1ad73df 100644
--- a/contrib/libs/icu/i18n/coptccal.h
+++ b/contrib/libs/icu/i18n/coptccal.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -145,7 +145,7 @@ public:
* @return return a polymorphic copy of this calendar.
* @internal
*/
- virtual CopticCalendar* clone() const;
+ virtual CopticCalendar* clone() const;
/**
* return the calendar type, "coptic"
diff --git a/contrib/libs/icu/i18n/cpdtrans.cpp b/contrib/libs/icu/i18n/cpdtrans.cpp
index 82ee54a77b..e882faa598 100644
--- a/contrib/libs/icu/i18n/cpdtrans.cpp
+++ b/contrib/libs/icu/i18n/cpdtrans.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -323,7 +323,7 @@ CompoundTransliterator& CompoundTransliterator::operator=(
/**
* Transliterator API.
*/
-CompoundTransliterator* CompoundTransliterator::clone() const {
+CompoundTransliterator* CompoundTransliterator::clone() const {
return new CompoundTransliterator(*this);
}
diff --git a/contrib/libs/icu/i18n/cpdtrans.h b/contrib/libs/icu/i18n/cpdtrans.h
index a2c7abbd69..efbabcf0f3 100644
--- a/contrib/libs/icu/i18n/cpdtrans.h
+++ b/contrib/libs/icu/i18n/cpdtrans.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -98,7 +98,7 @@ public:
/**
* Transliterator API.
*/
- virtual CompoundTransliterator* clone() const;
+ virtual CompoundTransliterator* clone() const;
/**
* Returns the number of transliterators in this chain.
diff --git a/contrib/libs/icu/i18n/csdetect.cpp b/contrib/libs/icu/i18n/csdetect.cpp
index babb308430..29bec6aba2 100644
--- a/contrib/libs/icu/i18n/csdetect.cpp
+++ b/contrib/libs/icu/i18n/csdetect.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -36,9 +36,9 @@ U_NAMESPACE_BEGIN
struct CSRecognizerInfo : public UMemory {
CSRecognizerInfo(CharsetRecognizer *recognizer, UBool isDefaultEnabled)
- : recognizer(recognizer), isDefaultEnabled(isDefaultEnabled) {}
+ : recognizer(recognizer), isDefaultEnabled(isDefaultEnabled) {}
- ~CSRecognizerInfo() {delete recognizer;}
+ ~CSRecognizerInfo() {delete recognizer;}
CharsetRecognizer *recognizer;
UBool isDefaultEnabled;
@@ -47,7 +47,7 @@ struct CSRecognizerInfo : public UMemory {
U_NAMESPACE_END
static icu::CSRecognizerInfo **fCSRecognizers = NULL;
-static icu::UInitOnce gCSRecognizersInitOnce = U_INITONCE_INITIALIZER;
+static icu::UInitOnce gCSRecognizersInitOnce = U_INITONCE_INITIALIZER;
static int32_t fCSRecognizers_size = 0;
U_CDECL_BEGIN
diff --git a/contrib/libs/icu/i18n/csdetect.h b/contrib/libs/icu/i18n/csdetect.h
index d4bfa75eef..c00f909882 100644
--- a/contrib/libs/icu/i18n/csdetect.h
+++ b/contrib/libs/icu/i18n/csdetect.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
diff --git a/contrib/libs/icu/i18n/csmatch.cpp b/contrib/libs/icu/i18n/csmatch.cpp
index 83bf531665..0a7680f46a 100644
--- a/contrib/libs/icu/i18n/csmatch.cpp
+++ b/contrib/libs/icu/i18n/csmatch.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
diff --git a/contrib/libs/icu/i18n/csmatch.h b/contrib/libs/icu/i18n/csmatch.h
index fe379ceea7..de4e715221 100644
--- a/contrib/libs/icu/i18n/csmatch.h
+++ b/contrib/libs/icu/i18n/csmatch.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
diff --git a/contrib/libs/icu/i18n/csr2022.cpp b/contrib/libs/icu/i18n/csr2022.cpp
index ff26e5e911..c6c8191923 100644
--- a/contrib/libs/icu/i18n/csr2022.cpp
+++ b/contrib/libs/icu/i18n/csr2022.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
diff --git a/contrib/libs/icu/i18n/csr2022.h b/contrib/libs/icu/i18n/csr2022.h
index cde9019b46..513ef934a6 100644
--- a/contrib/libs/icu/i18n/csr2022.h
+++ b/contrib/libs/icu/i18n/csr2022.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
diff --git a/contrib/libs/icu/i18n/csrecog.cpp b/contrib/libs/icu/i18n/csrecog.cpp
index 31fce5dd01..ce4c180f74 100644
--- a/contrib/libs/icu/i18n/csrecog.cpp
+++ b/contrib/libs/icu/i18n/csrecog.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
diff --git a/contrib/libs/icu/i18n/csrecog.h b/contrib/libs/icu/i18n/csrecog.h
index 713fd4e86b..443808eff4 100644
--- a/contrib/libs/icu/i18n/csrecog.h
+++ b/contrib/libs/icu/i18n/csrecog.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
diff --git a/contrib/libs/icu/i18n/csrmbcs.cpp b/contrib/libs/icu/i18n/csrmbcs.cpp
index 5579ba8ec3..d7cc30d317 100644
--- a/contrib/libs/icu/i18n/csrmbcs.cpp
+++ b/contrib/libs/icu/i18n/csrmbcs.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -166,7 +166,7 @@ int32_t CharsetRecog_mbcs::match_mbcs(InputText *det, const uint16_t commonChars
doubleByteCharCount++;
if (commonChars != 0) {
- if (binarySearch(commonChars, commonCharsLen, static_cast<uint16_t>(iter.charValue)) >= 0){
+ if (binarySearch(commonChars, commonCharsLen, static_cast<uint16_t>(iter.charValue)) >= 0){
commonCharCount += 1;
}
}
diff --git a/contrib/libs/icu/i18n/csrmbcs.h b/contrib/libs/icu/i18n/csrmbcs.h
index 8ccf1d56a9..ea0eb1be31 100644
--- a/contrib/libs/icu/i18n/csrmbcs.h
+++ b/contrib/libs/icu/i18n/csrmbcs.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
diff --git a/contrib/libs/icu/i18n/csrsbcs.cpp b/contrib/libs/icu/i18n/csrsbcs.cpp
index 0b0d8967e7..3d373507fd 100644
--- a/contrib/libs/icu/i18n/csrsbcs.cpp
+++ b/contrib/libs/icu/i18n/csrsbcs.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
diff --git a/contrib/libs/icu/i18n/csrsbcs.h b/contrib/libs/icu/i18n/csrsbcs.h
index 9768783679..27102ba53e 100644
--- a/contrib/libs/icu/i18n/csrsbcs.h
+++ b/contrib/libs/icu/i18n/csrsbcs.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
diff --git a/contrib/libs/icu/i18n/csrucode.cpp b/contrib/libs/icu/i18n/csrucode.cpp
index 59f2dbe284..d02681ca73 100644
--- a/contrib/libs/icu/i18n/csrucode.cpp
+++ b/contrib/libs/icu/i18n/csrucode.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
diff --git a/contrib/libs/icu/i18n/csrucode.h b/contrib/libs/icu/i18n/csrucode.h
index cef35447fb..ed7562db83 100644
--- a/contrib/libs/icu/i18n/csrucode.h
+++ b/contrib/libs/icu/i18n/csrucode.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
diff --git a/contrib/libs/icu/i18n/csrutf8.cpp b/contrib/libs/icu/i18n/csrutf8.cpp
index b42bd8b39e..64b8781256 100644
--- a/contrib/libs/icu/i18n/csrutf8.cpp
+++ b/contrib/libs/icu/i18n/csrutf8.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
diff --git a/contrib/libs/icu/i18n/csrutf8.h b/contrib/libs/icu/i18n/csrutf8.h
index 6089eb6f75..fb4eebe5ab 100644
--- a/contrib/libs/icu/i18n/csrutf8.h
+++ b/contrib/libs/icu/i18n/csrutf8.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
diff --git a/contrib/libs/icu/i18n/curramt.cpp b/contrib/libs/icu/i18n/curramt.cpp
index 6fd2ea2fda..cf6929d99f 100644
--- a/contrib/libs/icu/i18n/curramt.cpp
+++ b/contrib/libs/icu/i18n/curramt.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -19,12 +19,12 @@
U_NAMESPACE_BEGIN
-CurrencyAmount::CurrencyAmount(const Formattable& amount, ConstChar16Ptr isoCode,
+CurrencyAmount::CurrencyAmount(const Formattable& amount, ConstChar16Ptr isoCode,
UErrorCode& ec) :
Measure(amount, new CurrencyUnit(isoCode, ec), ec) {
}
-CurrencyAmount::CurrencyAmount(double amount, ConstChar16Ptr isoCode,
+CurrencyAmount::CurrencyAmount(double amount, ConstChar16Ptr isoCode,
UErrorCode& ec) :
Measure(Formattable(amount), new CurrencyUnit(isoCode, ec), ec) {
}
@@ -38,7 +38,7 @@ CurrencyAmount& CurrencyAmount::operator=(const CurrencyAmount& other) {
return *this;
}
-CurrencyAmount* CurrencyAmount::clone() const {
+CurrencyAmount* CurrencyAmount::clone() const {
return new CurrencyAmount(*this);
}
diff --git a/contrib/libs/icu/i18n/currfmt.cpp b/contrib/libs/icu/i18n/currfmt.cpp
index 0ad0492ee7..c553f03f6f 100644
--- a/contrib/libs/icu/i18n/currfmt.cpp
+++ b/contrib/libs/icu/i18n/currfmt.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -21,19 +21,19 @@
U_NAMESPACE_BEGIN
CurrencyFormat::CurrencyFormat(const Locale& locale, UErrorCode& ec) :
- MeasureFormat(locale, UMEASFMT_WIDTH_WIDE, ec)
+ MeasureFormat(locale, UMEASFMT_WIDTH_WIDE, ec)
{
}
CurrencyFormat::CurrencyFormat(const CurrencyFormat& other) :
- MeasureFormat(other)
+ MeasureFormat(other)
{
}
CurrencyFormat::~CurrencyFormat() {
}
-CurrencyFormat* CurrencyFormat::clone() const {
+CurrencyFormat* CurrencyFormat::clone() const {
return new CurrencyFormat(*this);
}
@@ -42,14 +42,14 @@ UnicodeString& CurrencyFormat::format(const Formattable& obj,
FieldPosition& pos,
UErrorCode& ec) const
{
- return getCurrencyFormatInternal().format(obj, appendTo, pos, ec);
+ return getCurrencyFormatInternal().format(obj, appendTo, pos, ec);
}
void CurrencyFormat::parseObject(const UnicodeString& source,
Formattable& result,
ParsePosition& pos) const
{
- CurrencyAmount* currAmt = getCurrencyFormatInternal().parseCurrency(source, pos);
+ CurrencyAmount* currAmt = getCurrencyFormatInternal().parseCurrency(source, pos);
if (currAmt != NULL) {
result.adoptObject(currAmt);
}
diff --git a/contrib/libs/icu/i18n/currfmt.h b/contrib/libs/icu/i18n/currfmt.h
index 69a031957b..70f2d17f0c 100644
--- a/contrib/libs/icu/i18n/currfmt.h
+++ b/contrib/libs/icu/i18n/currfmt.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -57,7 +57,7 @@ class CurrencyFormat : public MeasureFormat {
/**
* Override Format API.
*/
- virtual CurrencyFormat* clone() const;
+ virtual CurrencyFormat* clone() const;
using MeasureFormat::format;
diff --git a/contrib/libs/icu/i18n/currpinf.cpp b/contrib/libs/icu/i18n/currpinf.cpp
index af9c837af8..ab5a199d58 100644
--- a/contrib/libs/icu/i18n/currpinf.cpp
+++ b/contrib/libs/icu/i18n/currpinf.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -19,7 +19,7 @@
#include "unicode/locid.h"
#include "unicode/plurrule.h"
-#include "unicode/strenum.h"
+#include "unicode/strenum.h"
#include "unicode/ures.h"
#include "unicode/numsys.h"
#include "cstring.h"
@@ -63,27 +63,27 @@ static const char gDecimalFormatTag[]="decimalFormat";
static const char gCurrUnitPtnTag[]="CurrencyUnitPatterns";
CurrencyPluralInfo::CurrencyPluralInfo(UErrorCode& status)
-: fPluralCountToCurrencyUnitPattern(nullptr),
- fPluralRules(nullptr),
- fLocale(nullptr),
- fInternalStatus(U_ZERO_ERROR) {
+: fPluralCountToCurrencyUnitPattern(nullptr),
+ fPluralRules(nullptr),
+ fLocale(nullptr),
+ fInternalStatus(U_ZERO_ERROR) {
initialize(Locale::getDefault(), status);
}
CurrencyPluralInfo::CurrencyPluralInfo(const Locale& locale, UErrorCode& status)
-: fPluralCountToCurrencyUnitPattern(nullptr),
- fPluralRules(nullptr),
- fLocale(nullptr),
- fInternalStatus(U_ZERO_ERROR) {
+: fPluralCountToCurrencyUnitPattern(nullptr),
+ fPluralRules(nullptr),
+ fLocale(nullptr),
+ fInternalStatus(U_ZERO_ERROR) {
initialize(locale, status);
}
CurrencyPluralInfo::CurrencyPluralInfo(const CurrencyPluralInfo& info)
: UObject(info),
- fPluralCountToCurrencyUnitPattern(nullptr),
- fPluralRules(nullptr),
- fLocale(nullptr),
- fInternalStatus(U_ZERO_ERROR) {
+ fPluralCountToCurrencyUnitPattern(nullptr),
+ fPluralRules(nullptr),
+ fLocale(nullptr),
+ fInternalStatus(U_ZERO_ERROR) {
*this = info;
}
@@ -93,56 +93,56 @@ CurrencyPluralInfo::operator=(const CurrencyPluralInfo& info) {
return *this;
}
- fInternalStatus = info.fInternalStatus;
- if (U_FAILURE(fInternalStatus)) {
- // bail out early if the object we were copying from was already 'invalid'.
- return *this;
- }
-
+ fInternalStatus = info.fInternalStatus;
+ if (U_FAILURE(fInternalStatus)) {
+ // bail out early if the object we were copying from was already 'invalid'.
+ return *this;
+ }
+
deleteHash(fPluralCountToCurrencyUnitPattern);
- fPluralCountToCurrencyUnitPattern = initHash(fInternalStatus);
+ fPluralCountToCurrencyUnitPattern = initHash(fInternalStatus);
copyHash(info.fPluralCountToCurrencyUnitPattern,
- fPluralCountToCurrencyUnitPattern, fInternalStatus);
- if ( U_FAILURE(fInternalStatus) ) {
+ fPluralCountToCurrencyUnitPattern, fInternalStatus);
+ if ( U_FAILURE(fInternalStatus) ) {
return *this;
}
delete fPluralRules;
- fPluralRules = nullptr;
+ fPluralRules = nullptr;
delete fLocale;
- fLocale = nullptr;
-
- if (info.fPluralRules != nullptr) {
+ fLocale = nullptr;
+
+ if (info.fPluralRules != nullptr) {
fPluralRules = info.fPluralRules->clone();
- if (fPluralRules == nullptr) {
- fInternalStatus = U_MEMORY_ALLOCATION_ERROR;
- return *this;
- }
+ if (fPluralRules == nullptr) {
+ fInternalStatus = U_MEMORY_ALLOCATION_ERROR;
+ return *this;
+ }
}
- if (info.fLocale != nullptr) {
+ if (info.fLocale != nullptr) {
fLocale = info.fLocale->clone();
- if (fLocale == nullptr) {
- // Note: If clone had an error parameter, then we could check/set that instead.
- fInternalStatus = U_MEMORY_ALLOCATION_ERROR;
- return *this;
- }
- // If the other locale wasn't bogus, but our clone'd locale is bogus, then OOM happened
- // during the call to clone().
- if (!info.fLocale->isBogus() && fLocale->isBogus()) {
- fInternalStatus = U_MEMORY_ALLOCATION_ERROR;
- return *this;
- }
+ if (fLocale == nullptr) {
+ // Note: If clone had an error parameter, then we could check/set that instead.
+ fInternalStatus = U_MEMORY_ALLOCATION_ERROR;
+ return *this;
+ }
+ // If the other locale wasn't bogus, but our clone'd locale is bogus, then OOM happened
+ // during the call to clone().
+ if (!info.fLocale->isBogus() && fLocale->isBogus()) {
+ fInternalStatus = U_MEMORY_ALLOCATION_ERROR;
+ return *this;
+ }
}
return *this;
}
CurrencyPluralInfo::~CurrencyPluralInfo() {
deleteHash(fPluralCountToCurrencyUnitPattern);
- fPluralCountToCurrencyUnitPattern = nullptr;
+ fPluralCountToCurrencyUnitPattern = nullptr;
delete fPluralRules;
delete fLocale;
- fPluralRules = nullptr;
- fLocale = nullptr;
+ fPluralRules = nullptr;
+ fLocale = nullptr;
}
UBool
@@ -166,14 +166,14 @@ CurrencyPluralInfo::operator==(const CurrencyPluralInfo& info) const {
CurrencyPluralInfo*
CurrencyPluralInfo::clone() const {
- CurrencyPluralInfo* newObj = new CurrencyPluralInfo(*this);
- // Since clone doesn't have a 'status' parameter, the best we can do is return nullptr
- // if the new object was not full constructed properly (an error occurred).
- if (newObj != nullptr && U_FAILURE(newObj->fInternalStatus)) {
- delete newObj;
- newObj = nullptr;
- }
- return newObj;
+ CurrencyPluralInfo* newObj = new CurrencyPluralInfo(*this);
+ // Since clone doesn't have a 'status' parameter, the best we can do is return nullptr
+ // if the new object was not full constructed properly (an error occurred).
+ if (newObj != nullptr && U_FAILURE(newObj->fInternalStatus)) {
+ delete newObj;
+ newObj = nullptr;
+ }
+ return newObj;
}
const PluralRules*
@@ -186,15 +186,15 @@ CurrencyPluralInfo::getCurrencyPluralPattern(const UnicodeString& pluralCount,
UnicodeString& result) const {
const UnicodeString* currencyPluralPattern =
(UnicodeString*)fPluralCountToCurrencyUnitPattern->get(pluralCount);
- if (currencyPluralPattern == nullptr) {
+ if (currencyPluralPattern == nullptr) {
// fall back to "other"
if (pluralCount.compare(gPluralCountOther, 5)) {
currencyPluralPattern =
(UnicodeString*)fPluralCountToCurrencyUnitPattern->get(UnicodeString(TRUE, gPluralCountOther, 5));
}
- if (currencyPluralPattern == nullptr) {
+ if (currencyPluralPattern == nullptr) {
// no currencyUnitPatterns defined,
- // fallback to predefined default.
+ // fallback to predefined default.
// This should never happen when ICU resource files are
// available, since currencyUnitPattern of "other" is always
// defined in root.
@@ -215,7 +215,7 @@ void
CurrencyPluralInfo::setPluralRules(const UnicodeString& ruleDescription,
UErrorCode& status) {
if (U_SUCCESS(status)) {
- delete fPluralRules;
+ delete fPluralRules;
fPluralRules = PluralRules::createRules(ruleDescription, status);
}
}
@@ -225,15 +225,15 @@ CurrencyPluralInfo::setCurrencyPluralPattern(const UnicodeString& pluralCount,
const UnicodeString& pattern,
UErrorCode& status) {
if (U_SUCCESS(status)) {
- UnicodeString* oldValue = static_cast<UnicodeString*>(
- fPluralCountToCurrencyUnitPattern->get(pluralCount));
- delete oldValue;
- LocalPointer<UnicodeString> p(new UnicodeString(pattern), status);
- if (U_SUCCESS(status)) {
- // the p object allocated above will be owned by fPluralCountToCurrencyUnitPattern
- // after the call to put(), even if the method returns failure.
- fPluralCountToCurrencyUnitPattern->put(pluralCount, p.orphan(), status);
- }
+ UnicodeString* oldValue = static_cast<UnicodeString*>(
+ fPluralCountToCurrencyUnitPattern->get(pluralCount));
+ delete oldValue;
+ LocalPointer<UnicodeString> p(new UnicodeString(pattern), status);
+ if (U_SUCCESS(status)) {
+ // the p object allocated above will be owned by fPluralCountToCurrencyUnitPattern
+ // after the call to put(), even if the method returns failure.
+ fPluralCountToCurrencyUnitPattern->put(pluralCount, p.orphan(), status);
+ }
}
}
@@ -248,21 +248,21 @@ CurrencyPluralInfo::initialize(const Locale& loc, UErrorCode& status) {
return;
}
delete fLocale;
- fLocale = nullptr;
- delete fPluralRules;
- fPluralRules = nullptr;
-
+ fLocale = nullptr;
+ delete fPluralRules;
+ fPluralRules = nullptr;
+
fLocale = loc.clone();
- if (fLocale == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- // If the locale passed in wasn't bogus, but our clone'd locale is bogus, then OOM happened
- // during the call to loc.clone().
- if (!loc.isBogus() && fLocale->isBogus()) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
+ if (fLocale == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
}
+ // If the locale passed in wasn't bogus, but our clone'd locale is bogus, then OOM happened
+ // during the call to loc.clone().
+ if (!loc.isBogus() && fLocale->isBogus()) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
fPluralRules = PluralRules::forLocale(loc, status);
setupCurrencyPluralPattern(loc, status);
}
@@ -273,32 +273,32 @@ CurrencyPluralInfo::setupCurrencyPluralPattern(const Locale& loc, UErrorCode& st
return;
}
- deleteHash(fPluralCountToCurrencyUnitPattern);
+ deleteHash(fPluralCountToCurrencyUnitPattern);
fPluralCountToCurrencyUnitPattern = initHash(status);
if (U_FAILURE(status)) {
return;
}
- LocalPointer<NumberingSystem> ns(NumberingSystem::createInstance(loc, status), status);
- if (U_FAILURE(status)) {
- return;
- }
+ LocalPointer<NumberingSystem> ns(NumberingSystem::createInstance(loc, status), status);
+ if (U_FAILURE(status)) {
+ return;
+ }
UErrorCode ec = U_ZERO_ERROR;
- LocalUResourceBundlePointer rb(ures_open(nullptr, loc.getName(), &ec));
- LocalUResourceBundlePointer numElements(ures_getByKeyWithFallback(rb.getAlias(), gNumberElementsTag, nullptr, &ec));
- ures_getByKeyWithFallback(numElements.getAlias(), ns->getName(), rb.getAlias(), &ec);
- ures_getByKeyWithFallback(rb.getAlias(), gPatternsTag, rb.getAlias(), &ec);
+ LocalUResourceBundlePointer rb(ures_open(nullptr, loc.getName(), &ec));
+ LocalUResourceBundlePointer numElements(ures_getByKeyWithFallback(rb.getAlias(), gNumberElementsTag, nullptr, &ec));
+ ures_getByKeyWithFallback(numElements.getAlias(), ns->getName(), rb.getAlias(), &ec);
+ ures_getByKeyWithFallback(rb.getAlias(), gPatternsTag, rb.getAlias(), &ec);
int32_t ptnLen;
- const UChar* numberStylePattern = ures_getStringByKeyWithFallback(rb.getAlias(), gDecimalFormatTag, &ptnLen, &ec);
+ const UChar* numberStylePattern = ures_getStringByKeyWithFallback(rb.getAlias(), gDecimalFormatTag, &ptnLen, &ec);
// Fall back to "latn" if num sys specific pattern isn't there.
- if ( ec == U_MISSING_RESOURCE_ERROR && (uprv_strcmp(ns->getName(), gLatnTag) != 0)) {
+ if ( ec == U_MISSING_RESOURCE_ERROR && (uprv_strcmp(ns->getName(), gLatnTag) != 0)) {
ec = U_ZERO_ERROR;
- ures_getByKeyWithFallback(numElements.getAlias(), gLatnTag, rb.getAlias(), &ec);
- ures_getByKeyWithFallback(rb.getAlias(), gPatternsTag, rb.getAlias(), &ec);
- numberStylePattern = ures_getStringByKeyWithFallback(rb.getAlias(), gDecimalFormatTag, &ptnLen, &ec);
+ ures_getByKeyWithFallback(numElements.getAlias(), gLatnTag, rb.getAlias(), &ec);
+ ures_getByKeyWithFallback(rb.getAlias(), gPatternsTag, rb.getAlias(), &ec);
+ numberStylePattern = ures_getStringByKeyWithFallback(rb.getAlias(), gDecimalFormatTag, &ptnLen, &ec);
}
int32_t numberStylePatternLen = ptnLen;
- const UChar* negNumberStylePattern = nullptr;
+ const UChar* negNumberStylePattern = nullptr;
int32_t negNumberStylePatternLen = 0;
// TODO: Java
// parse to check whether there is ";" separator in the numberStylePattern
@@ -316,122 +316,122 @@ CurrencyPluralInfo::setupCurrencyPluralPattern(const Locale& loc, UErrorCode& st
}
if (U_FAILURE(ec)) {
- // If OOM occurred during the above code, then we want to report that back to the caller.
- if (ec == U_MEMORY_ALLOCATION_ERROR) {
- status = ec;
- }
+ // If OOM occurred during the above code, then we want to report that back to the caller.
+ if (ec == U_MEMORY_ALLOCATION_ERROR) {
+ status = ec;
+ }
return;
}
- LocalUResourceBundlePointer currRb(ures_open(U_ICUDATA_CURR, loc.getName(), &ec));
- LocalUResourceBundlePointer currencyRes(ures_getByKeyWithFallback(currRb.getAlias(), gCurrUnitPtnTag, nullptr, &ec));
+ LocalUResourceBundlePointer currRb(ures_open(U_ICUDATA_CURR, loc.getName(), &ec));
+ LocalUResourceBundlePointer currencyRes(ures_getByKeyWithFallback(currRb.getAlias(), gCurrUnitPtnTag, nullptr, &ec));
#ifdef CURRENCY_PLURAL_INFO_DEBUG
std::cout << "in set up\n";
#endif
- LocalPointer<StringEnumeration> keywords(fPluralRules->getKeywords(ec), ec);
+ LocalPointer<StringEnumeration> keywords(fPluralRules->getKeywords(ec), ec);
if (U_SUCCESS(ec)) {
const char* pluralCount;
- while (((pluralCount = keywords->next(nullptr, ec)) != nullptr) && U_SUCCESS(ec)) {
- int32_t ptnLength;
- UErrorCode err = U_ZERO_ERROR;
- const UChar* patternChars = ures_getStringByKeyWithFallback(currencyRes.getAlias(), pluralCount, &ptnLength, &err);
- if (err == U_MEMORY_ALLOCATION_ERROR || patternChars == nullptr) {
- ec = err;
- break;
- }
- if (U_SUCCESS(err) && ptnLength > 0) {
- UnicodeString* pattern = new UnicodeString(patternChars, ptnLength);
- if (pattern == nullptr) {
- ec = U_MEMORY_ALLOCATION_ERROR;
- break;
- }
+ while (((pluralCount = keywords->next(nullptr, ec)) != nullptr) && U_SUCCESS(ec)) {
+ int32_t ptnLength;
+ UErrorCode err = U_ZERO_ERROR;
+ const UChar* patternChars = ures_getStringByKeyWithFallback(currencyRes.getAlias(), pluralCount, &ptnLength, &err);
+ if (err == U_MEMORY_ALLOCATION_ERROR || patternChars == nullptr) {
+ ec = err;
+ break;
+ }
+ if (U_SUCCESS(err) && ptnLength > 0) {
+ UnicodeString* pattern = new UnicodeString(patternChars, ptnLength);
+ if (pattern == nullptr) {
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
#ifdef CURRENCY_PLURAL_INFO_DEBUG
- char result_1[1000];
- pattern->extract(0, pattern->length(), result_1, "UTF-8");
- std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n";
+ char result_1[1000];
+ pattern->extract(0, pattern->length(), result_1, "UTF-8");
+ std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n";
#endif
- pattern->findAndReplace(UnicodeString(TRUE, gPart0, 3),
- UnicodeString(numberStylePattern, numberStylePatternLen));
- pattern->findAndReplace(UnicodeString(TRUE, gPart1, 3), UnicodeString(TRUE, gTripleCurrencySign, 3));
-
- if (hasSeparator) {
- UnicodeString negPattern(patternChars, ptnLength);
- negPattern.findAndReplace(UnicodeString(TRUE, gPart0, 3),
- UnicodeString(negNumberStylePattern, negNumberStylePatternLen));
- negPattern.findAndReplace(UnicodeString(TRUE, gPart1, 3), UnicodeString(TRUE, gTripleCurrencySign, 3));
- pattern->append(gNumberPatternSeparator);
- pattern->append(negPattern);
- }
+ pattern->findAndReplace(UnicodeString(TRUE, gPart0, 3),
+ UnicodeString(numberStylePattern, numberStylePatternLen));
+ pattern->findAndReplace(UnicodeString(TRUE, gPart1, 3), UnicodeString(TRUE, gTripleCurrencySign, 3));
+
+ if (hasSeparator) {
+ UnicodeString negPattern(patternChars, ptnLength);
+ negPattern.findAndReplace(UnicodeString(TRUE, gPart0, 3),
+ UnicodeString(negNumberStylePattern, negNumberStylePatternLen));
+ negPattern.findAndReplace(UnicodeString(TRUE, gPart1, 3), UnicodeString(TRUE, gTripleCurrencySign, 3));
+ pattern->append(gNumberPatternSeparator);
+ pattern->append(negPattern);
+ }
#ifdef CURRENCY_PLURAL_INFO_DEBUG
- pattern->extract(0, pattern->length(), result_1, "UTF-8");
- std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n";
+ pattern->extract(0, pattern->length(), result_1, "UTF-8");
+ std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n";
#endif
- // the 'pattern' object allocated above will be owned by the fPluralCountToCurrencyUnitPattern after the call to
- // put(), even if the method returns failure.
- fPluralCountToCurrencyUnitPattern->put(UnicodeString(pluralCount, -1, US_INV), pattern, status);
+ // the 'pattern' object allocated above will be owned by the fPluralCountToCurrencyUnitPattern after the call to
+ // put(), even if the method returns failure.
+ fPluralCountToCurrencyUnitPattern->put(UnicodeString(pluralCount, -1, US_INV), pattern, status);
}
}
}
- // If OOM occurred during the above code, then we want to report that back to the caller.
- if (ec == U_MEMORY_ALLOCATION_ERROR) {
- status = ec;
- }
+ // If OOM occurred during the above code, then we want to report that back to the caller.
+ if (ec == U_MEMORY_ALLOCATION_ERROR) {
+ status = ec;
+ }
}
void
-CurrencyPluralInfo::deleteHash(Hashtable* hTable) {
- if ( hTable == nullptr ) {
+CurrencyPluralInfo::deleteHash(Hashtable* hTable) {
+ if ( hTable == nullptr ) {
return;
}
int32_t pos = UHASH_FIRST;
- const UHashElement* element = nullptr;
- while ( (element = hTable->nextElement(pos)) != nullptr ) {
+ const UHashElement* element = nullptr;
+ while ( (element = hTable->nextElement(pos)) != nullptr ) {
const UHashTok valueTok = element->value;
const UnicodeString* value = (UnicodeString*)valueTok.pointer;
delete value;
}
delete hTable;
- hTable = nullptr;
+ hTable = nullptr;
}
Hashtable*
CurrencyPluralInfo::initHash(UErrorCode& status) {
- if (U_FAILURE(status)) {
- return nullptr;
+ if (U_FAILURE(status)) {
+ return nullptr;
}
- LocalPointer<Hashtable> hTable(new Hashtable(TRUE, status), status);
- if (U_FAILURE(status)) {
- return nullptr;
+ LocalPointer<Hashtable> hTable(new Hashtable(TRUE, status), status);
+ if (U_FAILURE(status)) {
+ return nullptr;
}
hTable->setValueComparator(ValueComparator);
- return hTable.orphan();
+ return hTable.orphan();
}
void
CurrencyPluralInfo::copyHash(const Hashtable* source,
Hashtable* target,
UErrorCode& status) {
- if (U_FAILURE(status)) {
+ if (U_FAILURE(status)) {
return;
}
int32_t pos = UHASH_FIRST;
- const UHashElement* element = nullptr;
- if (source) {
- while ( (element = source->nextElement(pos)) != nullptr ) {
+ const UHashElement* element = nullptr;
+ if (source) {
+ while ( (element = source->nextElement(pos)) != nullptr ) {
const UHashTok keyTok = element->key;
const UnicodeString* key = (UnicodeString*)keyTok.pointer;
const UHashTok valueTok = element->value;
const UnicodeString* value = (UnicodeString*)valueTok.pointer;
- LocalPointer<UnicodeString> copy(new UnicodeString(*value), status);
- if (U_FAILURE(status)) {
- return;
- }
- // The HashTable owns the 'copy' object after the call to put().
- target->put(UnicodeString(*key), copy.orphan(), status);
- if (U_FAILURE(status)) {
+ LocalPointer<UnicodeString> copy(new UnicodeString(*value), status);
+ if (U_FAILURE(status)) {
return;
}
+ // The HashTable owns the 'copy' object after the call to put().
+ target->put(UnicodeString(*key), copy.orphan(), status);
+ if (U_FAILURE(status)) {
+ return;
+ }
}
}
}
diff --git a/contrib/libs/icu/i18n/currunit.cpp b/contrib/libs/icu/i18n/currunit.cpp
index 92bcf1268a..041653972e 100644
--- a/contrib/libs/icu/i18n/currunit.cpp
+++ b/contrib/libs/icu/i18n/currunit.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -16,93 +16,93 @@
#include "unicode/currunit.h"
#include "unicode/ustring.h"
-#include "unicode/uchar.h"
-#include "cstring.h"
-#include "uinvchar.h"
-#include "charstr.h"
-#include "ustr_imp.h"
-#include "measunit_impl.h"
+#include "unicode/uchar.h"
+#include "cstring.h"
+#include "uinvchar.h"
+#include "charstr.h"
+#include "ustr_imp.h"
+#include "measunit_impl.h"
U_NAMESPACE_BEGIN
-CurrencyUnit::CurrencyUnit(ConstChar16Ptr _isoCode, UErrorCode& ec) {
- // 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.
- // However, we allow a NUL-terminated empty string, which should have the same behavior as nullptr.
- // Consider NUL-terminated strings of length 1 or 2 as invalid.
- bool useDefault = false;
- if (U_FAILURE(ec) || _isoCode == nullptr || _isoCode[0] == 0) {
- useDefault = true;
- } else if (_isoCode[1] == 0 || _isoCode[2] == 0) {
- useDefault = true;
- ec = U_ILLEGAL_ARGUMENT_ERROR;
- } else if (!uprv_isInvariantUString(_isoCode, 3)) {
- // TODO: Perform a more strict ASCII check like in ICU4J isAlpha3Code?
- useDefault = true;
- ec = U_INVARIANT_CONVERSION_ERROR;
- } else {
- for (int32_t i=0; i<3; i++) {
- isoCode[i] = u_asciiToUpper(_isoCode[i]);
+CurrencyUnit::CurrencyUnit(ConstChar16Ptr _isoCode, UErrorCode& ec) {
+ // 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.
+ // However, we allow a NUL-terminated empty string, which should have the same behavior as nullptr.
+ // Consider NUL-terminated strings of length 1 or 2 as invalid.
+ bool useDefault = false;
+ if (U_FAILURE(ec) || _isoCode == nullptr || _isoCode[0] == 0) {
+ useDefault = true;
+ } else if (_isoCode[1] == 0 || _isoCode[2] == 0) {
+ useDefault = true;
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ } else if (!uprv_isInvariantUString(_isoCode, 3)) {
+ // TODO: Perform a more strict ASCII check like in ICU4J isAlpha3Code?
+ useDefault = true;
+ ec = U_INVARIANT_CONVERSION_ERROR;
+ } else {
+ for (int32_t i=0; i<3; i++) {
+ isoCode[i] = u_asciiToUpper(_isoCode[i]);
}
- isoCode[3] = 0;
+ isoCode[3] = 0;
}
- if (useDefault) {
- uprv_memcpy(isoCode, kDefaultCurrency, sizeof(UChar) * 4);
- }
- char simpleIsoCode[4];
- u_UCharsToChars(isoCode, simpleIsoCode, 4);
- initCurrency(simpleIsoCode);
-}
-
-CurrencyUnit::CurrencyUnit(StringPiece _isoCode, UErrorCode& ec) {
- // Note: unlike the old constructor, reject empty arguments with an error.
- char isoCodeBuffer[4];
- const char* isoCodeToUse;
- // uprv_memchr checks that the string contains no internal NULs
- if (_isoCode.length() != 3 || uprv_memchr(_isoCode.data(), 0, 3) != nullptr) {
- isoCodeToUse = kDefaultCurrency8;
- ec = U_ILLEGAL_ARGUMENT_ERROR;
- } else if (!uprv_isInvariantString(_isoCode.data(), 3)) {
- // TODO: Perform a more strict ASCII check like in ICU4J isAlpha3Code?
- isoCodeToUse = kDefaultCurrency8;
- ec = U_INVARIANT_CONVERSION_ERROR;
- } else {
- // Have to use isoCodeBuffer to ensure the string is NUL-terminated
- for (int32_t i=0; i<3; i++) {
- isoCodeBuffer[i] = uprv_toupper(_isoCode.data()[i]);
- }
- isoCodeBuffer[3] = 0;
- isoCodeToUse = isoCodeBuffer;
- }
- u_charsToUChars(isoCodeToUse, isoCode, 4);
- initCurrency(isoCodeToUse);
+ if (useDefault) {
+ uprv_memcpy(isoCode, kDefaultCurrency, sizeof(UChar) * 4);
+ }
+ char simpleIsoCode[4];
+ u_UCharsToChars(isoCode, simpleIsoCode, 4);
+ initCurrency(simpleIsoCode);
}
-CurrencyUnit::CurrencyUnit(const CurrencyUnit& other) : MeasureUnit(other) {
+CurrencyUnit::CurrencyUnit(StringPiece _isoCode, UErrorCode& ec) {
+ // Note: unlike the old constructor, reject empty arguments with an error.
+ char isoCodeBuffer[4];
+ const char* isoCodeToUse;
+ // uprv_memchr checks that the string contains no internal NULs
+ if (_isoCode.length() != 3 || uprv_memchr(_isoCode.data(), 0, 3) != nullptr) {
+ isoCodeToUse = kDefaultCurrency8;
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ } else if (!uprv_isInvariantString(_isoCode.data(), 3)) {
+ // TODO: Perform a more strict ASCII check like in ICU4J isAlpha3Code?
+ isoCodeToUse = kDefaultCurrency8;
+ ec = U_INVARIANT_CONVERSION_ERROR;
+ } else {
+ // Have to use isoCodeBuffer to ensure the string is NUL-terminated
+ for (int32_t i=0; i<3; i++) {
+ isoCodeBuffer[i] = uprv_toupper(_isoCode.data()[i]);
+ }
+ isoCodeBuffer[3] = 0;
+ isoCodeToUse = isoCodeBuffer;
+ }
+ u_charsToUChars(isoCodeToUse, isoCode, 4);
+ initCurrency(isoCodeToUse);
+}
+
+CurrencyUnit::CurrencyUnit(const CurrencyUnit& other) : MeasureUnit(other) {
u_strcpy(isoCode, other.isoCode);
}
-CurrencyUnit::CurrencyUnit(const MeasureUnit& other, UErrorCode& ec) : MeasureUnit(other) {
- // Make sure this is a currency.
- // OK to hard-code the string because we are comparing against another hard-coded string.
- if (uprv_strcmp("currency", getType()) != 0) {
- ec = U_ILLEGAL_ARGUMENT_ERROR;
- isoCode[0] = 0;
- } else {
- // Get the ISO Code from the subtype field.
- u_charsToUChars(getSubtype(), isoCode, 4);
- isoCode[3] = 0; // make 100% sure it is NUL-terminated
- }
-}
-
-CurrencyUnit::CurrencyUnit() : MeasureUnit() {
- u_strcpy(isoCode, kDefaultCurrency);
- char simpleIsoCode[4];
- u_UCharsToChars(isoCode, simpleIsoCode, 4);
- initCurrency(simpleIsoCode);
-}
-
+CurrencyUnit::CurrencyUnit(const MeasureUnit& other, UErrorCode& ec) : MeasureUnit(other) {
+ // Make sure this is a currency.
+ // OK to hard-code the string because we are comparing against another hard-coded string.
+ if (uprv_strcmp("currency", getType()) != 0) {
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ isoCode[0] = 0;
+ } else {
+ // Get the ISO Code from the subtype field.
+ u_charsToUChars(getSubtype(), isoCode, 4);
+ isoCode[3] = 0; // make 100% sure it is NUL-terminated
+ }
+}
+
+CurrencyUnit::CurrencyUnit() : MeasureUnit() {
+ u_strcpy(isoCode, kDefaultCurrency);
+ char simpleIsoCode[4];
+ u_UCharsToChars(isoCode, simpleIsoCode, 4);
+ initCurrency(simpleIsoCode);
+}
+
CurrencyUnit& CurrencyUnit::operator=(const CurrencyUnit& other) {
if (this == &other) {
return *this;
@@ -112,7 +112,7 @@ CurrencyUnit& CurrencyUnit::operator=(const CurrencyUnit& other) {
return *this;
}
-CurrencyUnit* CurrencyUnit::clone() const {
+CurrencyUnit* CurrencyUnit::clone() const {
return new CurrencyUnit(*this);
}
diff --git a/contrib/libs/icu/i18n/dangical.cpp b/contrib/libs/icu/i18n/dangical.cpp
index 02db40368e..70285744c1 100644
--- a/contrib/libs/icu/i18n/dangical.cpp
+++ b/contrib/libs/icu/i18n/dangical.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
@@ -65,7 +65,7 @@ DangiCalendar::~DangiCalendar()
{
}
-DangiCalendar*
+DangiCalendar*
DangiCalendar::clone() const
{
return new DangiCalendar(*this);
diff --git a/contrib/libs/icu/i18n/dangical.h b/contrib/libs/icu/i18n/dangical.h
index ece805e36d..a232b58b7c 100644
--- a/contrib/libs/icu/i18n/dangical.h
+++ b/contrib/libs/icu/i18n/dangical.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*****************************************************************************
@@ -66,7 +66,7 @@ class DangiCalendar : public ChineseCalendar {
* Clone.
* @internal
*/
- virtual DangiCalendar* clone() const;
+ virtual DangiCalendar* clone() const;
//----------------------------------------------------------------------
// Internal methods & astronomical calculations
diff --git a/contrib/libs/icu/i18n/datefmt.cpp b/contrib/libs/icu/i18n/datefmt.cpp
index a0e039cd50..aff92a8845 100644
--- a/contrib/libs/icu/i18n/datefmt.cpp
+++ b/contrib/libs/icu/i18n/datefmt.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -80,7 +80,7 @@ public:
fSkeleton(other.fSkeleton) { }
virtual ~DateFmtBestPatternKey();
virtual int32_t hashCode() const {
- return (int32_t)(37u * (uint32_t)LocaleCacheKey<DateFmtBestPattern>::hashCode() + (uint32_t)fSkeleton.hashCode());
+ return (int32_t)(37u * (uint32_t)LocaleCacheKey<DateFmtBestPattern>::hashCode() + (uint32_t)fSkeleton.hashCode());
}
virtual UBool operator==(const CacheKeyBase &other) const {
// reflexive
@@ -154,7 +154,7 @@ DateFormat& DateFormat::operator=(const DateFormat& other)
fCalendar = NULL;
}
if(other.fNumberFormat) {
- fNumberFormat = other.fNumberFormat->clone();
+ fNumberFormat = other.fNumberFormat->clone();
} else {
fNumberFormat = NULL;
}
@@ -460,15 +460,15 @@ DateFormat::createInstanceForSkeleton(
status = U_ILLEGAL_ARGUMENT_ERROR;
return NULL;
}
- Locale localeWithCalendar = locale;
- localeWithCalendar.setKeywordValue("calendar", calendar->getType(), status);
- if (U_FAILURE(status)) {
- return NULL;
- }
- DateFormat *result = createInstanceForSkeleton(skeleton, localeWithCalendar, status);
+ Locale localeWithCalendar = locale;
+ localeWithCalendar.setKeywordValue("calendar", calendar->getType(), status);
if (U_FAILURE(status)) {
return NULL;
}
+ DateFormat *result = createInstanceForSkeleton(skeleton, localeWithCalendar, status);
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
result->adoptCalendar(calendar.orphan());
return result;
}
@@ -503,7 +503,7 @@ DateFormat* U_EXPORT2
DateFormat::create(EStyle timeStyle, EStyle dateStyle, const Locale& locale)
{
UErrorCode status = U_ZERO_ERROR;
-#if U_PLATFORM_USES_ONLY_WIN32_API
+#if U_PLATFORM_USES_ONLY_WIN32_API
char buffer[8];
int32_t count = locale.getKeywordValue("compat", buffer, sizeof(buffer), status);
@@ -591,14 +591,14 @@ DateFormat::adoptNumberFormat(NumberFormat* newNumberFormat)
delete fNumberFormat;
fNumberFormat = newNumberFormat;
newNumberFormat->setParseIntegerOnly(TRUE);
- newNumberFormat->setGroupingUsed(FALSE);
+ newNumberFormat->setGroupingUsed(FALSE);
}
//----------------------------------------------------------------------
void
DateFormat::setNumberFormat(const NumberFormat& newNumberFormat)
{
- NumberFormat* newNumFmtClone = newNumberFormat.clone();
+ NumberFormat* newNumFmtClone = newNumberFormat.clone();
if (newNumFmtClone != NULL) {
adoptNumberFormat(newNumFmtClone);
}
@@ -744,7 +744,7 @@ DateFormat::setBooleanAttribute(UDateFormatBooleanAttribute attr,
UBool
DateFormat::getBooleanAttribute(UDateFormatBooleanAttribute attr, UErrorCode &/*status*/) const {
- return static_cast<UBool>(fBoolFlags.get(attr));
+ return static_cast<UBool>(fBoolFlags.get(attr));
}
U_NAMESPACE_END
diff --git a/contrib/libs/icu/i18n/dayperiodrules.cpp b/contrib/libs/icu/i18n/dayperiodrules.cpp
index e364ecb708..07e3076a50 100644
--- a/contrib/libs/icu/i18n/dayperiodrules.cpp
+++ b/contrib/libs/icu/i18n/dayperiodrules.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -174,7 +174,7 @@ struct DayPeriodRulesDataSink : public ResourceSink {
}
}
- void addCutoff(CutoffType type, const UnicodeString &hour_str, UErrorCode &errorCode) {
+ void addCutoff(CutoffType type, const UnicodeString &hour_str, UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) { return; }
if (type == CUTOFF_TYPE_UNKNOWN) {
@@ -340,7 +340,7 @@ const DayPeriodRules *DayPeriodRules::getInstance(const Locale &locale, UErrorCo
// does), return NULL.
if(U_FAILURE(errorCode)) { return NULL; }
- const char *localeCode = locale.getBaseName();
+ const char *localeCode = locale.getBaseName();
char name[ULOC_FULLNAME_CAPACITY];
char parentName[ULOC_FULLNAME_CAPACITY];
diff --git a/contrib/libs/icu/i18n/dayperiodrules.h b/contrib/libs/icu/i18n/dayperiodrules.h
index 610c6175bf..7effbf191d 100644
--- a/contrib/libs/icu/i18n/dayperiodrules.h
+++ b/contrib/libs/icu/i18n/dayperiodrules.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/dcfmtsym.cpp b/contrib/libs/icu/i18n/dcfmtsym.cpp
index 15418bfe65..e203a0549b 100644
--- a/contrib/libs/icu/i18n/dcfmtsym.cpp
+++ b/contrib/libs/icu/i18n/dcfmtsym.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -38,7 +38,7 @@
#include "uresimp.h"
#include "ureslocs.h"
#include "charstr.h"
-#include "uassert.h"
+#include "uassert.h"
// *****************************************************************************
// class DecimalFormatSymbols
@@ -66,7 +66,7 @@ static const UChar INTL_CURRENCY_SYMBOL_STR[] = {0xa4, 0xa4, 0};
static const char *gNumberElementKeys[DecimalFormatSymbols::kFormatSymbolCount] = {
"decimal",
"group",
- NULL, /* #11897: the <list> symbol is NOT the pattern separator symbol */
+ NULL, /* #11897: the <list> 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(), currPattern(NULL) {
+ : UObject(), locale(), currPattern(NULL) {
initialize(locale, status, TRUE);
}
@@ -106,17 +106,17 @@ 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), currPattern(NULL) {
+ : UObject(), locale(loc), currPattern(NULL) {
initialize(locale, status);
}
-DecimalFormatSymbols::DecimalFormatSymbols(const Locale& loc, const NumberingSystem& ns, UErrorCode& status)
- : UObject(), locale(loc), currPattern(NULL) {
- initialize(locale, status, FALSE, &ns);
-}
-
+DecimalFormatSymbols::DecimalFormatSymbols(const Locale& loc, const NumberingSystem& ns, UErrorCode& status)
+ : UObject(), locale(loc), currPattern(NULL) {
+ initialize(locale, status, FALSE, &ns);
+}
+
DecimalFormatSymbols::DecimalFormatSymbols()
- : UObject(), locale(Locale::getRoot()), currPattern(NULL) {
+ : UObject(), locale(Locale::getRoot()), currPattern(NULL) {
*validLocale = *actualLocale = 0;
initialize();
}
@@ -166,8 +166,8 @@ DecimalFormatSymbols::operator=(const DecimalFormatSymbols& rhs)
uprv_strcpy(actualLocale, rhs.actualLocale);
fIsCustomCurrencySymbol = rhs.fIsCustomCurrencySymbol;
fIsCustomIntlCurrencySymbol = rhs.fIsCustomIntlCurrencySymbol;
- fCodePointZero = rhs.fCodePointZero;
- currPattern = rhs.currPattern;
+ fCodePointZero = rhs.fCodePointZero;
+ currPattern = rhs.currPattern;
}
return *this;
}
@@ -199,7 +199,7 @@ DecimalFormatSymbols::operator==(const DecimalFormatSymbols& that) const
return FALSE;
}
}
- // No need to check fCodePointZero since it is based on fSymbols
+ // No need to check fCodePointZero since it is based on fSymbols
return locale == that.locale &&
uprv_strcmp(validLocale, that.validLocale) == 0 &&
uprv_strcmp(actualLocale, that.actualLocale) == 0;
@@ -345,8 +345,8 @@ CurrencySpacingSink::~CurrencySpacingSink() {}
} // namespace
void
-DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status,
- UBool useLastResortData, const NumberingSystem* ns)
+DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status,
+ UBool useLastResortData, const NumberingSystem* ns)
{
if (U_FAILURE(status)) { return; }
*validLocale = *actualLocale = 0;
@@ -358,13 +358,13 @@ DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status,
// Next get the numbering system for this locale and set zero digit
// and the digit string based on the numbering system for the locale
//
- LocalPointer<NumberingSystem> nsLocal;
- if (ns == nullptr) {
- // Use the numbering system according to the locale.
- // Save it into a LocalPointer so it gets cleaned up.
- nsLocal.adoptInstead(NumberingSystem::createInstance(loc, status));
- ns = nsLocal.getAlias();
- }
+ LocalPointer<NumberingSystem> nsLocal;
+ if (ns == nullptr) {
+ // Use the numbering system according to the locale.
+ // Save it into a LocalPointer so it gets cleaned up.
+ nsLocal.adoptInstead(NumberingSystem::createInstance(loc, status));
+ ns = nsLocal.getAlias();
+ }
const char *nsName;
if (U_SUCCESS(status) && ns->getRadix() == 10 && !ns->isAlgorithmic()) {
nsName = ns->getName();
@@ -436,33 +436,33 @@ DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status,
// Let the monetary number separators equal the default number separators if necessary.
sink.resolveMissingMonetarySeparators(fSymbols);
- // Resolve codePointZero
- UChar32 tempCodePointZero = -1;
- for (int32_t i=0; i<=9; i++) {
- const UnicodeString& stringDigit = getConstDigitSymbol(i);
- if (stringDigit.countChar32() != 1) {
- tempCodePointZero = -1;
- break;
- }
- UChar32 cp = stringDigit.char32At(0);
- if (i == 0) {
- tempCodePointZero = cp;
- } else if (cp != tempCodePointZero + i) {
- tempCodePointZero = -1;
- break;
- }
- }
- fCodePointZero = tempCodePointZero;
-
- // Get the default currency from the currency API.
+ // Resolve codePointZero
+ UChar32 tempCodePointZero = -1;
+ for (int32_t i=0; i<=9; i++) {
+ const UnicodeString& stringDigit = getConstDigitSymbol(i);
+ if (stringDigit.countChar32() != 1) {
+ tempCodePointZero = -1;
+ break;
+ }
+ UChar32 cp = stringDigit.char32At(0);
+ if (i == 0) {
+ tempCodePointZero = cp;
+ } else if (cp != tempCodePointZero + i) {
+ tempCodePointZero = -1;
+ break;
+ }
+ }
+ fCodePointZero = tempCodePointZero;
+
+ // Get the default currency from the currency API.
UErrorCode internalStatus = U_ZERO_ERROR; // don't propagate failures out
UChar curriso[4];
UnicodeString tempStr;
- int32_t currisoLength = ucurr_forLocale(locStr, curriso, UPRV_LENGTHOF(curriso), &internalStatus);
- if (U_SUCCESS(internalStatus) && currisoLength == 3) {
- setCurrency(curriso, status);
- } else {
- setCurrency(nullptr, status);
+ int32_t currisoLength = ucurr_forLocale(locStr, curriso, UPRV_LENGTHOF(curriso), &internalStatus);
+ if (U_SUCCESS(internalStatus) && currisoLength == 3) {
+ setCurrency(curriso, status);
+ } else {
+ setCurrency(nullptr, status);
}
// Currency Spacing.
@@ -510,56 +510,56 @@ DecimalFormatSymbols::initialize() {
fSymbols[kExponentMultiplicationSymbol] = (UChar)0xd7; // 'x' multiplication symbol for exponents
fIsCustomCurrencySymbol = FALSE;
fIsCustomIntlCurrencySymbol = FALSE;
- fCodePointZero = 0x30;
- U_ASSERT(fCodePointZero == fSymbols[kZeroDigitSymbol].char32At(0));
- currPattern = nullptr;
+ fCodePointZero = 0x30;
+ U_ASSERT(fCodePointZero == fSymbols[kZeroDigitSymbol].char32At(0));
+ currPattern = nullptr;
}
-void DecimalFormatSymbols::setCurrency(const UChar* currency, UErrorCode& status) {
- // TODO: If this method is made public:
- // - Adopt ICU4J behavior of not allowing currency to be null.
- // - Also verify that the length of currency is 3.
- if (!currency) {
- return;
- }
-
- UnicodeString tempStr;
- uprv_getStaticCurrencyName(currency, locale.getName(), tempStr, status);
- if (U_SUCCESS(status)) {
- fSymbols[kIntlCurrencySymbol].setTo(currency, 3);
- fSymbols[kCurrencySymbol] = tempStr;
- }
-
- char cc[4]={0};
- u_UCharsToChars(currency, cc, 3);
-
- /* An explicit currency was requested */
- // TODO(ICU-13297): Move this data loading logic into a centralized place
- UErrorCode localStatus = U_ZERO_ERROR;
- LocalUResourceBundlePointer rbTop(ures_open(U_ICUDATA_CURR, locale.getName(), &localStatus));
- LocalUResourceBundlePointer rb(
- ures_getByKeyWithFallback(rbTop.getAlias(), "Currencies", NULL, &localStatus));
- ures_getByKeyWithFallback(rb.getAlias(), cc, rb.getAlias(), &localStatus);
- if(U_SUCCESS(localStatus) && ures_getSize(rb.getAlias())>2) { // the length is 3 if more data is present
- ures_getByIndex(rb.getAlias(), 2, rb.getAlias(), &localStatus);
- int32_t currPatternLen = 0;
- currPattern =
- ures_getStringByIndex(rb.getAlias(), (int32_t)0, &currPatternLen, &localStatus);
- UnicodeString decimalSep =
- ures_getUnicodeStringByIndex(rb.getAlias(), (int32_t)1, &localStatus);
- UnicodeString groupingSep =
- ures_getUnicodeStringByIndex(rb.getAlias(), (int32_t)2, &localStatus);
- if(U_SUCCESS(localStatus)){
- fSymbols[kMonetaryGroupingSeparatorSymbol] = groupingSep;
- fSymbols[kMonetarySeparatorSymbol] = decimalSep;
- //pattern.setTo(TRUE, currPattern, currPatternLen);
- }
- }
- /* else An explicit currency was requested and is unknown or locale data is malformed. */
- /* ucurr_* API will get the correct value later on. */
-}
-
+void DecimalFormatSymbols::setCurrency(const UChar* currency, UErrorCode& status) {
+ // TODO: If this method is made public:
+ // - Adopt ICU4J behavior of not allowing currency to be null.
+ // - Also verify that the length of currency is 3.
+ if (!currency) {
+ return;
+ }
+
+ UnicodeString tempStr;
+ uprv_getStaticCurrencyName(currency, locale.getName(), tempStr, status);
+ if (U_SUCCESS(status)) {
+ fSymbols[kIntlCurrencySymbol].setTo(currency, 3);
+ fSymbols[kCurrencySymbol] = tempStr;
+ }
+
+ char cc[4]={0};
+ u_UCharsToChars(currency, cc, 3);
+
+ /* An explicit currency was requested */
+ // TODO(ICU-13297): Move this data loading logic into a centralized place
+ UErrorCode localStatus = U_ZERO_ERROR;
+ LocalUResourceBundlePointer rbTop(ures_open(U_ICUDATA_CURR, locale.getName(), &localStatus));
+ LocalUResourceBundlePointer rb(
+ ures_getByKeyWithFallback(rbTop.getAlias(), "Currencies", NULL, &localStatus));
+ ures_getByKeyWithFallback(rb.getAlias(), cc, rb.getAlias(), &localStatus);
+ if(U_SUCCESS(localStatus) && ures_getSize(rb.getAlias())>2) { // the length is 3 if more data is present
+ ures_getByIndex(rb.getAlias(), 2, rb.getAlias(), &localStatus);
+ int32_t currPatternLen = 0;
+ currPattern =
+ ures_getStringByIndex(rb.getAlias(), (int32_t)0, &currPatternLen, &localStatus);
+ UnicodeString decimalSep =
+ ures_getUnicodeStringByIndex(rb.getAlias(), (int32_t)1, &localStatus);
+ UnicodeString groupingSep =
+ ures_getUnicodeStringByIndex(rb.getAlias(), (int32_t)2, &localStatus);
+ if(U_SUCCESS(localStatus)){
+ fSymbols[kMonetaryGroupingSeparatorSymbol] = groupingSep;
+ fSymbols[kMonetarySeparatorSymbol] = decimalSep;
+ //pattern.setTo(TRUE, currPattern, currPatternLen);
+ }
+ }
+ /* else An explicit currency was requested and is unknown or locale data is malformed. */
+ /* ucurr_* API will get the correct value later on. */
+}
+
Locale
DecimalFormatSymbols::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
U_LOCALE_BASED(locBased, *this);
diff --git a/contrib/libs/icu/i18n/decContext.cpp b/contrib/libs/icu/i18n/decContext.cpp
index 6ec6d32afb..41a6e6f80e 100644
--- a/contrib/libs/icu/i18n/decContext.cpp
+++ b/contrib/libs/icu/i18n/decContext.cpp
@@ -1,432 +1,432 @@
-// © 2016 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html
-/* ------------------------------------------------------------------ */
-/* Decimal Context module */
-/* ------------------------------------------------------------------ */
-/* Copyright (c) IBM Corporation, 2000-2012. All rights reserved. */
-/* */
-/* This software is made available under the terms of the */
-/* ICU License -- ICU 1.8.1 and later. */
-/* */
-/* The description and User's Guide ("The decNumber C Library") for */
-/* this software is called decNumber.pdf. This document is */
-/* available, together with arithmetic and format specifications, */
-/* testcases, and Web links, on the General Decimal Arithmetic page. */
-/* */
-/* Please send comments, suggestions, and corrections to the author: */
-/* mfc@uk.ibm.com */
-/* Mike Cowlishaw, IBM Fellow */
-/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */
-/* ------------------------------------------------------------------ */
-/* This module comprises the routines for handling arithmetic */
-/* context structures. */
-/* ------------------------------------------------------------------ */
-
-#include <string.h> /* for strcmp */
-#include <stdio.h> /* for printf if DECCHECK */
-#include "decContext.h" /* context and base types */
-#include "decNumberLocal.h" /* decNumber local types, etc. */
-
-#if 0 /* ICU: No need to test endianness at runtime. */
-/* compile-time endian tester [assumes sizeof(Int)>1] */
-static const Int mfcone=1; /* constant 1 */
-static const Flag *mfctop=(Flag *)&mfcone; /* -> top byte */
-#define LITEND *mfctop /* named flag; 1=little-endian */
-#endif
-
-/* ------------------------------------------------------------------ */
-/* decContextClearStatus -- clear bits in current status */
-/* */
-/* context is the context structure to be queried */
-/* mask indicates the bits to be cleared (the status bit that */
-/* corresponds to each 1 bit in the mask is cleared) */
-/* returns context */
-/* */
-/* No error is possible. */
-/* ------------------------------------------------------------------ */
-U_CAPI decContext * U_EXPORT2 uprv_decContextClearStatus(decContext *context, uInt mask) {
- context->status&=~mask;
- return context;
- } /* decContextClearStatus */
-
-/* ------------------------------------------------------------------ */
-/* decContextDefault -- initialize a context structure */
-/* */
-/* context is the structure to be initialized */
-/* kind selects the required set of default values, one of: */
-/* DEC_INIT_BASE -- select ANSI X3-274 defaults */
-/* DEC_INIT_DECIMAL32 -- select IEEE 754 defaults, 32-bit */
-/* DEC_INIT_DECIMAL64 -- select IEEE 754 defaults, 64-bit */
-/* DEC_INIT_DECIMAL128 -- select IEEE 754 defaults, 128-bit */
-/* For any other value a valid context is returned, but with */
-/* Invalid_operation set in the status field. */
-/* returns a context structure with the appropriate initial values. */
-/* ------------------------------------------------------------------ */
-U_CAPI decContext * U_EXPORT2 uprv_decContextDefault(decContext *context, Int kind) {
- /* set defaults... */
- context->digits=9; /* 9 digits */
- context->emax=DEC_MAX_EMAX; /* 9-digit exponents */
- context->emin=DEC_MIN_EMIN; /* .. balanced */
- context->round=DEC_ROUND_HALF_UP; /* 0.5 rises */
- context->traps=DEC_Errors; /* all but informational */
- context->status=0; /* cleared */
- context->clamp=0; /* no clamping */
- #if DECSUBSET
- context->extended=0; /* cleared */
- #endif
- switch (kind) {
- case DEC_INIT_BASE:
- /* [use defaults] */
- break;
- case DEC_INIT_DECIMAL32:
- context->digits=7; /* digits */
- context->emax=96; /* Emax */
- context->emin=-95; /* Emin */
- context->round=DEC_ROUND_HALF_EVEN; /* 0.5 to nearest even */
- context->traps=0; /* no traps set */
- context->clamp=1; /* clamp exponents */
- #if DECSUBSET
- context->extended=1; /* set */
- #endif
- break;
- case DEC_INIT_DECIMAL64:
- context->digits=16; /* digits */
- context->emax=384; /* Emax */
- context->emin=-383; /* Emin */
- context->round=DEC_ROUND_HALF_EVEN; /* 0.5 to nearest even */
- context->traps=0; /* no traps set */
- context->clamp=1; /* clamp exponents */
- #if DECSUBSET
- context->extended=1; /* set */
- #endif
- break;
- case DEC_INIT_DECIMAL128:
- context->digits=34; /* digits */
- context->emax=6144; /* Emax */
- context->emin=-6143; /* Emin */
- context->round=DEC_ROUND_HALF_EVEN; /* 0.5 to nearest even */
- context->traps=0; /* no traps set */
- context->clamp=1; /* clamp exponents */
- #if DECSUBSET
- context->extended=1; /* set */
- #endif
- break;
-
- default: /* invalid Kind */
- /* use defaults, and .. */
- uprv_decContextSetStatus(context, DEC_Invalid_operation); /* trap */
- }
-
- return context;} /* decContextDefault */
-
-/* ------------------------------------------------------------------ */
-/* decContextGetRounding -- return current rounding mode */
-/* */
-/* context is the context structure to be queried */
-/* returns the rounding mode */
-/* */
-/* No error is possible. */
-/* ------------------------------------------------------------------ */
-U_CAPI enum rounding U_EXPORT2 uprv_decContextGetRounding(decContext *context) {
- return context->round;
- } /* decContextGetRounding */
-
-/* ------------------------------------------------------------------ */
-/* decContextGetStatus -- return current status */
-/* */
-/* context is the context structure to be queried */
-/* returns status */
-/* */
-/* No error is possible. */
-/* ------------------------------------------------------------------ */
-U_CAPI uInt U_EXPORT2 uprv_decContextGetStatus(decContext *context) {
- return context->status;
- } /* decContextGetStatus */
-
-/* ------------------------------------------------------------------ */
-/* decContextRestoreStatus -- restore bits in current status */
-/* */
-/* context is the context structure to be updated */
-/* newstatus is the source for the bits to be restored */
-/* mask indicates the bits to be restored (the status bit that */
-/* corresponds to each 1 bit in the mask is set to the value of */
-/* the correspnding bit in newstatus) */
-/* returns context */
-/* */
-/* No error is possible. */
-/* ------------------------------------------------------------------ */
-U_CAPI decContext * U_EXPORT2 uprv_decContextRestoreStatus(decContext *context,
- uInt newstatus, uInt mask) {
- context->status&=~mask; /* clear the selected bits */
- context->status|=(mask&newstatus); /* or in the new bits */
- return context;
- } /* decContextRestoreStatus */
-
-/* ------------------------------------------------------------------ */
-/* decContextSaveStatus -- save bits in current status */
-/* */
-/* context is the context structure to be queried */
-/* mask indicates the bits to be saved (the status bits that */
-/* correspond to each 1 bit in the mask are saved) */
-/* returns the AND of the mask and the current status */
-/* */
-/* No error is possible. */
-/* ------------------------------------------------------------------ */
-U_CAPI uInt U_EXPORT2 uprv_decContextSaveStatus(decContext *context, uInt mask) {
- return context->status&mask;
- } /* decContextSaveStatus */
-
-/* ------------------------------------------------------------------ */
-/* decContextSetRounding -- set current rounding mode */
-/* */
-/* context is the context structure to be updated */
-/* newround is the value which will replace the current mode */
-/* returns context */
-/* */
-/* No error is possible. */
-/* ------------------------------------------------------------------ */
-U_CAPI decContext * U_EXPORT2 uprv_decContextSetRounding(decContext *context,
- enum rounding newround) {
- context->round=newround;
- return context;
- } /* decContextSetRounding */
-
-/* ------------------------------------------------------------------ */
-/* decContextSetStatus -- set status and raise trap if appropriate */
-/* */
-/* context is the context structure to be updated */
-/* status is the DEC_ exception code */
-/* returns the context structure */
-/* */
-/* Control may never return from this routine, if there is a signal */
-/* handler and it takes a long jump. */
-/* ------------------------------------------------------------------ */
-U_CAPI decContext * U_EXPORT2 uprv_decContextSetStatus(decContext *context, uInt status) {
- context->status|=status;
-#if 0 /* ICU: Do not raise signals. */
- if (status & context->traps) raise(SIGFPE);
-#endif
- return context;} /* decContextSetStatus */
-
-/* ------------------------------------------------------------------ */
-/* decContextSetStatusFromString -- set status from a string + trap */
-/* */
-/* context is the context structure to be updated */
-/* string is a string exactly equal to one that might be returned */
-/* by decContextStatusToString */
-/* */
-/* The status bit corresponding to the string is set, and a trap */
-/* is raised if appropriate. */
-/* */
-/* returns the context structure, unless the string is equal to */
-/* DEC_Condition_MU or is not recognized. In these cases NULL is */
-/* returned. */
-/* ------------------------------------------------------------------ */
-U_CAPI decContext * U_EXPORT2 uprv_decContextSetStatusFromString(decContext *context,
- const char *string) {
- if (strcmp(string, DEC_Condition_CS)==0)
- return uprv_decContextSetStatus(context, DEC_Conversion_syntax);
- if (strcmp(string, DEC_Condition_DZ)==0)
- return uprv_decContextSetStatus(context, DEC_Division_by_zero);
- if (strcmp(string, DEC_Condition_DI)==0)
- return uprv_decContextSetStatus(context, DEC_Division_impossible);
- if (strcmp(string, DEC_Condition_DU)==0)
- return uprv_decContextSetStatus(context, DEC_Division_undefined);
- if (strcmp(string, DEC_Condition_IE)==0)
- return uprv_decContextSetStatus(context, DEC_Inexact);
- if (strcmp(string, DEC_Condition_IS)==0)
- return uprv_decContextSetStatus(context, DEC_Insufficient_storage);
- if (strcmp(string, DEC_Condition_IC)==0)
- return uprv_decContextSetStatus(context, DEC_Invalid_context);
- if (strcmp(string, DEC_Condition_IO)==0)
- return uprv_decContextSetStatus(context, DEC_Invalid_operation);
- #if DECSUBSET
- if (strcmp(string, DEC_Condition_LD)==0)
- return uprv_decContextSetStatus(context, DEC_Lost_digits);
- #endif
- if (strcmp(string, DEC_Condition_OV)==0)
- return uprv_decContextSetStatus(context, DEC_Overflow);
- if (strcmp(string, DEC_Condition_PA)==0)
- return uprv_decContextSetStatus(context, DEC_Clamped);
- if (strcmp(string, DEC_Condition_RO)==0)
- return uprv_decContextSetStatus(context, DEC_Rounded);
- if (strcmp(string, DEC_Condition_SU)==0)
- return uprv_decContextSetStatus(context, DEC_Subnormal);
- if (strcmp(string, DEC_Condition_UN)==0)
- return uprv_decContextSetStatus(context, DEC_Underflow);
- if (strcmp(string, DEC_Condition_ZE)==0)
- return context;
- return NULL; /* Multiple status, or unknown */
- } /* decContextSetStatusFromString */
-
-/* ------------------------------------------------------------------ */
-/* decContextSetStatusFromStringQuiet -- set status from a string */
-/* */
-/* context is the context structure to be updated */
-/* string is a string exactly equal to one that might be returned */
-/* by decContextStatusToString */
-/* */
-/* The status bit corresponding to the string is set; no trap is */
-/* raised. */
-/* */
-/* returns the context structure, unless the string is equal to */
-/* DEC_Condition_MU or is not recognized. In these cases NULL is */
-/* returned. */
-/* ------------------------------------------------------------------ */
-U_CAPI decContext * U_EXPORT2 uprv_decContextSetStatusFromStringQuiet(decContext *context,
- const char *string) {
- if (strcmp(string, DEC_Condition_CS)==0)
- return uprv_decContextSetStatusQuiet(context, DEC_Conversion_syntax);
- if (strcmp(string, DEC_Condition_DZ)==0)
- return uprv_decContextSetStatusQuiet(context, DEC_Division_by_zero);
- if (strcmp(string, DEC_Condition_DI)==0)
- return uprv_decContextSetStatusQuiet(context, DEC_Division_impossible);
- if (strcmp(string, DEC_Condition_DU)==0)
- return uprv_decContextSetStatusQuiet(context, DEC_Division_undefined);
- if (strcmp(string, DEC_Condition_IE)==0)
- return uprv_decContextSetStatusQuiet(context, DEC_Inexact);
- if (strcmp(string, DEC_Condition_IS)==0)
- return uprv_decContextSetStatusQuiet(context, DEC_Insufficient_storage);
- if (strcmp(string, DEC_Condition_IC)==0)
- return uprv_decContextSetStatusQuiet(context, DEC_Invalid_context);
- if (strcmp(string, DEC_Condition_IO)==0)
- return uprv_decContextSetStatusQuiet(context, DEC_Invalid_operation);
- #if DECSUBSET
- if (strcmp(string, DEC_Condition_LD)==0)
- return uprv_decContextSetStatusQuiet(context, DEC_Lost_digits);
- #endif
- if (strcmp(string, DEC_Condition_OV)==0)
- return uprv_decContextSetStatusQuiet(context, DEC_Overflow);
- if (strcmp(string, DEC_Condition_PA)==0)
- return uprv_decContextSetStatusQuiet(context, DEC_Clamped);
- if (strcmp(string, DEC_Condition_RO)==0)
- return uprv_decContextSetStatusQuiet(context, DEC_Rounded);
- if (strcmp(string, DEC_Condition_SU)==0)
- return uprv_decContextSetStatusQuiet(context, DEC_Subnormal);
- if (strcmp(string, DEC_Condition_UN)==0)
- return uprv_decContextSetStatusQuiet(context, DEC_Underflow);
- if (strcmp(string, DEC_Condition_ZE)==0)
- return context;
- return NULL; /* Multiple status, or unknown */
- } /* decContextSetStatusFromStringQuiet */
-
-/* ------------------------------------------------------------------ */
-/* decContextSetStatusQuiet -- set status without trap */
-/* */
-/* context is the context structure to be updated */
-/* status is the DEC_ exception code */
-/* returns the context structure */
-/* */
-/* No error is possible. */
-/* ------------------------------------------------------------------ */
-U_CAPI decContext * U_EXPORT2 uprv_decContextSetStatusQuiet(decContext *context, uInt status) {
- context->status|=status;
- return context;} /* decContextSetStatusQuiet */
-
-/* ------------------------------------------------------------------ */
-/* decContextStatusToString -- convert status flags to a string */
-/* */
-/* context is a context with valid status field */
-/* */
-/* returns a constant string describing the condition. If multiple */
-/* (or no) flags are set, a generic constant message is returned. */
-/* ------------------------------------------------------------------ */
-U_CAPI const char * U_EXPORT2 uprv_decContextStatusToString(const decContext *context) {
- Int status=context->status;
-
- /* test the five IEEE first, as some of the others are ambiguous when */
- /* DECEXTFLAG=0 */
- if (status==DEC_Invalid_operation ) return DEC_Condition_IO;
- if (status==DEC_Division_by_zero ) return DEC_Condition_DZ;
- if (status==DEC_Overflow ) return DEC_Condition_OV;
- if (status==DEC_Underflow ) return DEC_Condition_UN;
- if (status==DEC_Inexact ) return DEC_Condition_IE;
-
- if (status==DEC_Division_impossible ) return DEC_Condition_DI;
- if (status==DEC_Division_undefined ) return DEC_Condition_DU;
- if (status==DEC_Rounded ) return DEC_Condition_RO;
- if (status==DEC_Clamped ) return DEC_Condition_PA;
- if (status==DEC_Subnormal ) return DEC_Condition_SU;
- if (status==DEC_Conversion_syntax ) return DEC_Condition_CS;
- if (status==DEC_Insufficient_storage ) return DEC_Condition_IS;
- if (status==DEC_Invalid_context ) return DEC_Condition_IC;
- #if DECSUBSET
- if (status==DEC_Lost_digits ) return DEC_Condition_LD;
- #endif
- if (status==0 ) return DEC_Condition_ZE;
- return DEC_Condition_MU; /* Multiple errors */
- } /* decContextStatusToString */
-
-/* ------------------------------------------------------------------ */
-/* decContextTestEndian -- test whether DECLITEND is set correctly */
-/* */
-/* quiet is 1 to suppress message; 0 otherwise */
-/* returns 0 if DECLITEND is correct */
-/* 1 if DECLITEND is incorrect and should be 1 */
-/* -1 if DECLITEND is incorrect and should be 0 */
-/* */
-/* A message is displayed if the return value is not 0 and quiet==0. */
-/* */
-/* No error is possible. */
-/* ------------------------------------------------------------------ */
-#if 0 /* ICU: Unused function. Anyway, do not call printf(). */
-U_CAPI Int U_EXPORT2 uprv_decContextTestEndian(Flag quiet) {
- Int res=0; /* optimist */
- uInt dle=(uInt)DECLITEND; /* unsign */
- if (dle>1) dle=1; /* ensure 0 or 1 */
-
- if (LITEND!=DECLITEND) {
- const char *adj;
- if (!quiet) {
- if (LITEND) adj="little";
- else adj="big";
- printf("Warning: DECLITEND is set to %d, but this computer appears to be %s-endian\n",
- DECLITEND, adj);
- }
- res=(Int)LITEND-dle;
- }
- return res;
- } /* decContextTestEndian */
-#endif
-
-/* ------------------------------------------------------------------ */
-/* decContextTestSavedStatus -- test bits in saved status */
-/* */
-/* oldstatus is the status word to be tested */
-/* mask indicates the bits to be tested (the oldstatus bits that */
-/* correspond to each 1 bit in the mask are tested) */
-/* returns 1 if any of the tested bits are 1, or 0 otherwise */
-/* */
-/* No error is possible. */
-/* ------------------------------------------------------------------ */
-U_CAPI uInt U_EXPORT2 uprv_decContextTestSavedStatus(uInt oldstatus, uInt mask) {
- return (oldstatus&mask)!=0;
- } /* decContextTestSavedStatus */
-
-/* ------------------------------------------------------------------ */
-/* decContextTestStatus -- test bits in current status */
-/* */
-/* context is the context structure to be updated */
-/* mask indicates the bits to be tested (the status bits that */
-/* correspond to each 1 bit in the mask are tested) */
-/* returns 1 if any of the tested bits are 1, or 0 otherwise */
-/* */
-/* No error is possible. */
-/* ------------------------------------------------------------------ */
-U_CAPI uInt U_EXPORT2 uprv_decContextTestStatus(decContext *context, uInt mask) {
- return (context->status&mask)!=0;
- } /* decContextTestStatus */
-
-/* ------------------------------------------------------------------ */
-/* decContextZeroStatus -- clear all status bits */
-/* */
-/* context is the context structure to be updated */
-/* returns context */
-/* */
-/* No error is possible. */
-/* ------------------------------------------------------------------ */
-U_CAPI decContext * U_EXPORT2 uprv_decContextZeroStatus(decContext *context) {
- context->status=0;
- return context;
- } /* decContextZeroStatus */
-
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/* ------------------------------------------------------------------ */
+/* Decimal Context module */
+/* ------------------------------------------------------------------ */
+/* Copyright (c) IBM Corporation, 2000-2012. All rights reserved. */
+/* */
+/* This software is made available under the terms of the */
+/* ICU License -- ICU 1.8.1 and later. */
+/* */
+/* The description and User's Guide ("The decNumber C Library") for */
+/* this software is called decNumber.pdf. This document is */
+/* available, together with arithmetic and format specifications, */
+/* testcases, and Web links, on the General Decimal Arithmetic page. */
+/* */
+/* Please send comments, suggestions, and corrections to the author: */
+/* mfc@uk.ibm.com */
+/* Mike Cowlishaw, IBM Fellow */
+/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */
+/* ------------------------------------------------------------------ */
+/* This module comprises the routines for handling arithmetic */
+/* context structures. */
+/* ------------------------------------------------------------------ */
+
+#include <string.h> /* for strcmp */
+#include <stdio.h> /* for printf if DECCHECK */
+#include "decContext.h" /* context and base types */
+#include "decNumberLocal.h" /* decNumber local types, etc. */
+
+#if 0 /* ICU: No need to test endianness at runtime. */
+/* compile-time endian tester [assumes sizeof(Int)>1] */
+static const Int mfcone=1; /* constant 1 */
+static const Flag *mfctop=(Flag *)&mfcone; /* -> top byte */
+#define LITEND *mfctop /* named flag; 1=little-endian */
+#endif
+
+/* ------------------------------------------------------------------ */
+/* decContextClearStatus -- clear bits in current status */
+/* */
+/* context is the context structure to be queried */
+/* mask indicates the bits to be cleared (the status bit that */
+/* corresponds to each 1 bit in the mask is cleared) */
+/* returns context */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI decContext * U_EXPORT2 uprv_decContextClearStatus(decContext *context, uInt mask) {
+ context->status&=~mask;
+ return context;
+ } /* decContextClearStatus */
+
+/* ------------------------------------------------------------------ */
+/* decContextDefault -- initialize a context structure */
+/* */
+/* context is the structure to be initialized */
+/* kind selects the required set of default values, one of: */
+/* DEC_INIT_BASE -- select ANSI X3-274 defaults */
+/* DEC_INIT_DECIMAL32 -- select IEEE 754 defaults, 32-bit */
+/* DEC_INIT_DECIMAL64 -- select IEEE 754 defaults, 64-bit */
+/* DEC_INIT_DECIMAL128 -- select IEEE 754 defaults, 128-bit */
+/* For any other value a valid context is returned, but with */
+/* Invalid_operation set in the status field. */
+/* returns a context structure with the appropriate initial values. */
+/* ------------------------------------------------------------------ */
+U_CAPI decContext * U_EXPORT2 uprv_decContextDefault(decContext *context, Int kind) {
+ /* set defaults... */
+ context->digits=9; /* 9 digits */
+ context->emax=DEC_MAX_EMAX; /* 9-digit exponents */
+ context->emin=DEC_MIN_EMIN; /* .. balanced */
+ context->round=DEC_ROUND_HALF_UP; /* 0.5 rises */
+ context->traps=DEC_Errors; /* all but informational */
+ context->status=0; /* cleared */
+ context->clamp=0; /* no clamping */
+ #if DECSUBSET
+ context->extended=0; /* cleared */
+ #endif
+ switch (kind) {
+ case DEC_INIT_BASE:
+ /* [use defaults] */
+ break;
+ case DEC_INIT_DECIMAL32:
+ context->digits=7; /* digits */
+ context->emax=96; /* Emax */
+ context->emin=-95; /* Emin */
+ context->round=DEC_ROUND_HALF_EVEN; /* 0.5 to nearest even */
+ context->traps=0; /* no traps set */
+ context->clamp=1; /* clamp exponents */
+ #if DECSUBSET
+ context->extended=1; /* set */
+ #endif
+ break;
+ case DEC_INIT_DECIMAL64:
+ context->digits=16; /* digits */
+ context->emax=384; /* Emax */
+ context->emin=-383; /* Emin */
+ context->round=DEC_ROUND_HALF_EVEN; /* 0.5 to nearest even */
+ context->traps=0; /* no traps set */
+ context->clamp=1; /* clamp exponents */
+ #if DECSUBSET
+ context->extended=1; /* set */
+ #endif
+ break;
+ case DEC_INIT_DECIMAL128:
+ context->digits=34; /* digits */
+ context->emax=6144; /* Emax */
+ context->emin=-6143; /* Emin */
+ context->round=DEC_ROUND_HALF_EVEN; /* 0.5 to nearest even */
+ context->traps=0; /* no traps set */
+ context->clamp=1; /* clamp exponents */
+ #if DECSUBSET
+ context->extended=1; /* set */
+ #endif
+ break;
+
+ default: /* invalid Kind */
+ /* use defaults, and .. */
+ uprv_decContextSetStatus(context, DEC_Invalid_operation); /* trap */
+ }
+
+ return context;} /* decContextDefault */
+
+/* ------------------------------------------------------------------ */
+/* decContextGetRounding -- return current rounding mode */
+/* */
+/* context is the context structure to be queried */
+/* returns the rounding mode */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI enum rounding U_EXPORT2 uprv_decContextGetRounding(decContext *context) {
+ return context->round;
+ } /* decContextGetRounding */
+
+/* ------------------------------------------------------------------ */
+/* decContextGetStatus -- return current status */
+/* */
+/* context is the context structure to be queried */
+/* returns status */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI uInt U_EXPORT2 uprv_decContextGetStatus(decContext *context) {
+ return context->status;
+ } /* decContextGetStatus */
+
+/* ------------------------------------------------------------------ */
+/* decContextRestoreStatus -- restore bits in current status */
+/* */
+/* context is the context structure to be updated */
+/* newstatus is the source for the bits to be restored */
+/* mask indicates the bits to be restored (the status bit that */
+/* corresponds to each 1 bit in the mask is set to the value of */
+/* the correspnding bit in newstatus) */
+/* returns context */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI decContext * U_EXPORT2 uprv_decContextRestoreStatus(decContext *context,
+ uInt newstatus, uInt mask) {
+ context->status&=~mask; /* clear the selected bits */
+ context->status|=(mask&newstatus); /* or in the new bits */
+ return context;
+ } /* decContextRestoreStatus */
+
+/* ------------------------------------------------------------------ */
+/* decContextSaveStatus -- save bits in current status */
+/* */
+/* context is the context structure to be queried */
+/* mask indicates the bits to be saved (the status bits that */
+/* correspond to each 1 bit in the mask are saved) */
+/* returns the AND of the mask and the current status */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI uInt U_EXPORT2 uprv_decContextSaveStatus(decContext *context, uInt mask) {
+ return context->status&mask;
+ } /* decContextSaveStatus */
+
+/* ------------------------------------------------------------------ */
+/* decContextSetRounding -- set current rounding mode */
+/* */
+/* context is the context structure to be updated */
+/* newround is the value which will replace the current mode */
+/* returns context */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI decContext * U_EXPORT2 uprv_decContextSetRounding(decContext *context,
+ enum rounding newround) {
+ context->round=newround;
+ return context;
+ } /* decContextSetRounding */
+
+/* ------------------------------------------------------------------ */
+/* decContextSetStatus -- set status and raise trap if appropriate */
+/* */
+/* context is the context structure to be updated */
+/* status is the DEC_ exception code */
+/* returns the context structure */
+/* */
+/* Control may never return from this routine, if there is a signal */
+/* handler and it takes a long jump. */
+/* ------------------------------------------------------------------ */
+U_CAPI decContext * U_EXPORT2 uprv_decContextSetStatus(decContext *context, uInt status) {
+ context->status|=status;
+#if 0 /* ICU: Do not raise signals. */
+ if (status & context->traps) raise(SIGFPE);
+#endif
+ return context;} /* decContextSetStatus */
+
+/* ------------------------------------------------------------------ */
+/* decContextSetStatusFromString -- set status from a string + trap */
+/* */
+/* context is the context structure to be updated */
+/* string is a string exactly equal to one that might be returned */
+/* by decContextStatusToString */
+/* */
+/* The status bit corresponding to the string is set, and a trap */
+/* is raised if appropriate. */
+/* */
+/* returns the context structure, unless the string is equal to */
+/* DEC_Condition_MU or is not recognized. In these cases NULL is */
+/* returned. */
+/* ------------------------------------------------------------------ */
+U_CAPI decContext * U_EXPORT2 uprv_decContextSetStatusFromString(decContext *context,
+ const char *string) {
+ if (strcmp(string, DEC_Condition_CS)==0)
+ return uprv_decContextSetStatus(context, DEC_Conversion_syntax);
+ if (strcmp(string, DEC_Condition_DZ)==0)
+ return uprv_decContextSetStatus(context, DEC_Division_by_zero);
+ if (strcmp(string, DEC_Condition_DI)==0)
+ return uprv_decContextSetStatus(context, DEC_Division_impossible);
+ if (strcmp(string, DEC_Condition_DU)==0)
+ return uprv_decContextSetStatus(context, DEC_Division_undefined);
+ if (strcmp(string, DEC_Condition_IE)==0)
+ return uprv_decContextSetStatus(context, DEC_Inexact);
+ if (strcmp(string, DEC_Condition_IS)==0)
+ return uprv_decContextSetStatus(context, DEC_Insufficient_storage);
+ if (strcmp(string, DEC_Condition_IC)==0)
+ return uprv_decContextSetStatus(context, DEC_Invalid_context);
+ if (strcmp(string, DEC_Condition_IO)==0)
+ return uprv_decContextSetStatus(context, DEC_Invalid_operation);
+ #if DECSUBSET
+ if (strcmp(string, DEC_Condition_LD)==0)
+ return uprv_decContextSetStatus(context, DEC_Lost_digits);
+ #endif
+ if (strcmp(string, DEC_Condition_OV)==0)
+ return uprv_decContextSetStatus(context, DEC_Overflow);
+ if (strcmp(string, DEC_Condition_PA)==0)
+ return uprv_decContextSetStatus(context, DEC_Clamped);
+ if (strcmp(string, DEC_Condition_RO)==0)
+ return uprv_decContextSetStatus(context, DEC_Rounded);
+ if (strcmp(string, DEC_Condition_SU)==0)
+ return uprv_decContextSetStatus(context, DEC_Subnormal);
+ if (strcmp(string, DEC_Condition_UN)==0)
+ return uprv_decContextSetStatus(context, DEC_Underflow);
+ if (strcmp(string, DEC_Condition_ZE)==0)
+ return context;
+ return NULL; /* Multiple status, or unknown */
+ } /* decContextSetStatusFromString */
+
+/* ------------------------------------------------------------------ */
+/* decContextSetStatusFromStringQuiet -- set status from a string */
+/* */
+/* context is the context structure to be updated */
+/* string is a string exactly equal to one that might be returned */
+/* by decContextStatusToString */
+/* */
+/* The status bit corresponding to the string is set; no trap is */
+/* raised. */
+/* */
+/* returns the context structure, unless the string is equal to */
+/* DEC_Condition_MU or is not recognized. In these cases NULL is */
+/* returned. */
+/* ------------------------------------------------------------------ */
+U_CAPI decContext * U_EXPORT2 uprv_decContextSetStatusFromStringQuiet(decContext *context,
+ const char *string) {
+ if (strcmp(string, DEC_Condition_CS)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Conversion_syntax);
+ if (strcmp(string, DEC_Condition_DZ)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Division_by_zero);
+ if (strcmp(string, DEC_Condition_DI)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Division_impossible);
+ if (strcmp(string, DEC_Condition_DU)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Division_undefined);
+ if (strcmp(string, DEC_Condition_IE)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Inexact);
+ if (strcmp(string, DEC_Condition_IS)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Insufficient_storage);
+ if (strcmp(string, DEC_Condition_IC)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Invalid_context);
+ if (strcmp(string, DEC_Condition_IO)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Invalid_operation);
+ #if DECSUBSET
+ if (strcmp(string, DEC_Condition_LD)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Lost_digits);
+ #endif
+ if (strcmp(string, DEC_Condition_OV)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Overflow);
+ if (strcmp(string, DEC_Condition_PA)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Clamped);
+ if (strcmp(string, DEC_Condition_RO)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Rounded);
+ if (strcmp(string, DEC_Condition_SU)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Subnormal);
+ if (strcmp(string, DEC_Condition_UN)==0)
+ return uprv_decContextSetStatusQuiet(context, DEC_Underflow);
+ if (strcmp(string, DEC_Condition_ZE)==0)
+ return context;
+ return NULL; /* Multiple status, or unknown */
+ } /* decContextSetStatusFromStringQuiet */
+
+/* ------------------------------------------------------------------ */
+/* decContextSetStatusQuiet -- set status without trap */
+/* */
+/* context is the context structure to be updated */
+/* status is the DEC_ exception code */
+/* returns the context structure */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI decContext * U_EXPORT2 uprv_decContextSetStatusQuiet(decContext *context, uInt status) {
+ context->status|=status;
+ return context;} /* decContextSetStatusQuiet */
+
+/* ------------------------------------------------------------------ */
+/* decContextStatusToString -- convert status flags to a string */
+/* */
+/* context is a context with valid status field */
+/* */
+/* returns a constant string describing the condition. If multiple */
+/* (or no) flags are set, a generic constant message is returned. */
+/* ------------------------------------------------------------------ */
+U_CAPI const char * U_EXPORT2 uprv_decContextStatusToString(const decContext *context) {
+ Int status=context->status;
+
+ /* test the five IEEE first, as some of the others are ambiguous when */
+ /* DECEXTFLAG=0 */
+ if (status==DEC_Invalid_operation ) return DEC_Condition_IO;
+ if (status==DEC_Division_by_zero ) return DEC_Condition_DZ;
+ if (status==DEC_Overflow ) return DEC_Condition_OV;
+ if (status==DEC_Underflow ) return DEC_Condition_UN;
+ if (status==DEC_Inexact ) return DEC_Condition_IE;
+
+ if (status==DEC_Division_impossible ) return DEC_Condition_DI;
+ if (status==DEC_Division_undefined ) return DEC_Condition_DU;
+ if (status==DEC_Rounded ) return DEC_Condition_RO;
+ if (status==DEC_Clamped ) return DEC_Condition_PA;
+ if (status==DEC_Subnormal ) return DEC_Condition_SU;
+ if (status==DEC_Conversion_syntax ) return DEC_Condition_CS;
+ if (status==DEC_Insufficient_storage ) return DEC_Condition_IS;
+ if (status==DEC_Invalid_context ) return DEC_Condition_IC;
+ #if DECSUBSET
+ if (status==DEC_Lost_digits ) return DEC_Condition_LD;
+ #endif
+ if (status==0 ) return DEC_Condition_ZE;
+ return DEC_Condition_MU; /* Multiple errors */
+ } /* decContextStatusToString */
+
+/* ------------------------------------------------------------------ */
+/* decContextTestEndian -- test whether DECLITEND is set correctly */
+/* */
+/* quiet is 1 to suppress message; 0 otherwise */
+/* returns 0 if DECLITEND is correct */
+/* 1 if DECLITEND is incorrect and should be 1 */
+/* -1 if DECLITEND is incorrect and should be 0 */
+/* */
+/* A message is displayed if the return value is not 0 and quiet==0. */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+#if 0 /* ICU: Unused function. Anyway, do not call printf(). */
+U_CAPI Int U_EXPORT2 uprv_decContextTestEndian(Flag quiet) {
+ Int res=0; /* optimist */
+ uInt dle=(uInt)DECLITEND; /* unsign */
+ if (dle>1) dle=1; /* ensure 0 or 1 */
+
+ if (LITEND!=DECLITEND) {
+ const char *adj;
+ if (!quiet) {
+ if (LITEND) adj="little";
+ else adj="big";
+ printf("Warning: DECLITEND is set to %d, but this computer appears to be %s-endian\n",
+ DECLITEND, adj);
+ }
+ res=(Int)LITEND-dle;
+ }
+ return res;
+ } /* decContextTestEndian */
+#endif
+
+/* ------------------------------------------------------------------ */
+/* decContextTestSavedStatus -- test bits in saved status */
+/* */
+/* oldstatus is the status word to be tested */
+/* mask indicates the bits to be tested (the oldstatus bits that */
+/* correspond to each 1 bit in the mask are tested) */
+/* returns 1 if any of the tested bits are 1, or 0 otherwise */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI uInt U_EXPORT2 uprv_decContextTestSavedStatus(uInt oldstatus, uInt mask) {
+ return (oldstatus&mask)!=0;
+ } /* decContextTestSavedStatus */
+
+/* ------------------------------------------------------------------ */
+/* decContextTestStatus -- test bits in current status */
+/* */
+/* context is the context structure to be updated */
+/* mask indicates the bits to be tested (the status bits that */
+/* correspond to each 1 bit in the mask are tested) */
+/* returns 1 if any of the tested bits are 1, or 0 otherwise */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI uInt U_EXPORT2 uprv_decContextTestStatus(decContext *context, uInt mask) {
+ return (context->status&mask)!=0;
+ } /* decContextTestStatus */
+
+/* ------------------------------------------------------------------ */
+/* decContextZeroStatus -- clear all status bits */
+/* */
+/* context is the context structure to be updated */
+/* returns context */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI decContext * U_EXPORT2 uprv_decContextZeroStatus(decContext *context) {
+ context->status=0;
+ return context;
+ } /* decContextZeroStatus */
+
diff --git a/contrib/libs/icu/i18n/decContext.h b/contrib/libs/icu/i18n/decContext.h
index e145777d1e..92bf477410 100644
--- a/contrib/libs/icu/i18n/decContext.h
+++ b/contrib/libs/icu/i18n/decContext.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/* ------------------------------------------------------------------ */
/* Decimal Context module header */
diff --git a/contrib/libs/icu/i18n/decNumber.cpp b/contrib/libs/icu/i18n/decNumber.cpp
index cee2f8e949..115887ac7f 100644
--- a/contrib/libs/icu/i18n/decNumber.cpp
+++ b/contrib/libs/icu/i18n/decNumber.cpp
@@ -1,8190 +1,8190 @@
-// © 2016 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html
-/* ------------------------------------------------------------------ */
-/* Decimal Number arithmetic module */
-/* ------------------------------------------------------------------ */
-/* Copyright (c) IBM Corporation, 2000-2014. All rights reserved. */
-/* */
-/* This software is made available under the terms of the */
-/* ICU License -- ICU 1.8.1 and later. */
-/* */
-/* The description and User's Guide ("The decNumber C Library") for */
-/* this software is called decNumber.pdf. This document is */
-/* available, together with arithmetic and format specifications, */
-/* testcases, and Web links, on the General Decimal Arithmetic page. */
-/* */
-/* Please send comments, suggestions, and corrections to the author: */
-/* mfc@uk.ibm.com */
-/* Mike Cowlishaw, IBM Fellow */
-/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */
-/* ------------------------------------------------------------------ */
-
-/* Modified version, for use from within ICU.
- * Renamed public functions, to avoid an unwanted export of the
- * standard names from the ICU library.
- *
- * Use ICU's uprv_malloc() and uprv_free()
- *
- * Revert comment syntax to plain C
- *
- * Remove a few compiler warnings.
- */
-
-/* This module comprises the routines for arbitrary-precision General */
-/* Decimal Arithmetic as defined in the specification which may be */
-/* found on the General Decimal Arithmetic pages. It implements both */
-/* the full ('extended') arithmetic and the simpler ('subset') */
-/* arithmetic. */
-/* */
-/* Usage notes: */
-/* */
-/* 1. This code is ANSI C89 except: */
-/* */
-/* a) C99 line comments (double forward slash) are used. (Most C */
-/* compilers accept these. If yours does not, a simple script */
-/* can be used to convert them to ANSI C comments.) */
-/* */
-/* b) Types from C99 stdint.h are used. If you do not have this */
-/* header file, see the User's Guide section of the decNumber */
-/* documentation; this lists the necessary definitions. */
-/* */
-/* c) If DECDPUN>4 or DECUSE64=1, the C99 64-bit int64_t and */
-/* uint64_t types may be used. To avoid these, set DECUSE64=0 */
-/* and DECDPUN<=4 (see documentation). */
-/* */
-/* The code also conforms to C99 restrictions; in particular, */
-/* strict aliasing rules are observed. */
-/* */
-/* 2. The decNumber format which this library uses is optimized for */
-/* efficient processing of relatively short numbers; in particular */
-/* it allows the use of fixed sized structures and minimizes copy */
-/* and move operations. It does, however, support arbitrary */
-/* precision (up to 999,999,999 digits) and arbitrary exponent */
-/* range (Emax in the range 0 through 999,999,999 and Emin in the */
-/* range -999,999,999 through 0). Mathematical functions (for */
-/* example decNumberExp) as identified below are restricted more */
-/* tightly: digits, emax, and -emin in the context must be <= */
-/* DEC_MAX_MATH (999999), and their operand(s) must be within */
-/* these bounds. */
-/* */
-/* 3. Logical functions are further restricted; their operands must */
-/* be finite, positive, have an exponent of zero, and all digits */
-/* must be either 0 or 1. The result will only contain digits */
-/* which are 0 or 1 (and will have exponent=0 and a sign of 0). */
-/* */
-/* 4. Operands to operator functions are never modified unless they */
-/* are also specified to be the result number (which is always */
-/* permitted). Other than that case, operands must not overlap. */
-/* */
-/* 5. Error handling: the type of the error is ORed into the status */
-/* flags in the current context (decContext structure). The */
-/* SIGFPE signal is then raised if the corresponding trap-enabler */
-/* flag in the decContext is set (is 1). */
-/* */
-/* It is the responsibility of the caller to clear the status */
-/* flags as required. */
-/* */
-/* The result of any routine which returns a number will always */
-/* be a valid number (which may be a special value, such as an */
-/* Infinity or NaN). */
-/* */
-/* 6. The decNumber format is not an exchangeable concrete */
-/* representation as it comprises fields which may be machine- */
-/* dependent (packed or unpacked, or special length, for example). */
-/* Canonical conversions to and from strings are provided; other */
-/* conversions are available in separate modules. */
-/* */
-/* 7. Normally, input operands are assumed to be valid. Set DECCHECK */
-/* to 1 for extended operand checking (including NULL operands). */
-/* Results are undefined if a badly-formed structure (or a NULL */
-/* pointer to a structure) is provided, though with DECCHECK */
-/* enabled the operator routines are protected against exceptions. */
-/* (Except if the result pointer is NULL, which is unrecoverable.) */
-/* */
-/* However, the routines will never cause exceptions if they are */
-/* given well-formed operands, even if the value of the operands */
-/* is inappropriate for the operation and DECCHECK is not set. */
-/* (Except for SIGFPE, as and where documented.) */
-/* */
-/* 8. Subset arithmetic is available only if DECSUBSET is set to 1. */
-/* ------------------------------------------------------------------ */
-/* Implementation notes for maintenance of this module: */
-/* */
-/* 1. Storage leak protection: Routines which use malloc are not */
-/* permitted to use return for fastpath or error exits (i.e., */
-/* they follow strict structured programming conventions). */
-/* Instead they have a do{}while(0); construct surrounding the */
-/* code which is protected -- break may be used to exit this. */
-/* Other routines can safely use the return statement inline. */
-/* */
-/* Storage leak accounting can be enabled using DECALLOC. */
-/* */
-/* 2. All loops use the for(;;) construct. Any do construct does */
-/* not loop; it is for allocation protection as just described. */
-/* */
-/* 3. Setting status in the context must always be the very last */
-/* action in a routine, as non-0 status may raise a trap and hence */
-/* the call to set status may not return (if the handler uses long */
-/* jump). Therefore all cleanup must be done first. In general, */
-/* to achieve this status is accumulated and is only applied just */
-/* before return by calling decContextSetStatus (via decStatus). */
-/* */
-/* Routines which allocate storage cannot, in general, use the */
-/* 'top level' routines which could cause a non-returning */
-/* transfer of control. The decXxxxOp routines are safe (do not */
-/* call decStatus even if traps are set in the context) and should */
-/* be used instead (they are also a little faster). */
-/* */
-/* 4. Exponent checking is minimized by allowing the exponent to */
-/* grow outside its limits during calculations, provided that */
-/* the decFinalize function is called later. Multiplication and */
-/* division, and intermediate calculations in exponentiation, */
-/* require more careful checks because of the risk of 31-bit */
-/* overflow (the most negative valid exponent is -1999999997, for */
-/* a 999999999-digit number with adjusted exponent of -999999999). */
-/* */
-/* 5. Rounding is deferred until finalization of results, with any */
-/* 'off to the right' data being represented as a single digit */
-/* residue (in the range -1 through 9). This avoids any double- */
-/* rounding when more than one shortening takes place (for */
-/* example, when a result is subnormal). */
-/* */
-/* 6. The digits count is allowed to rise to a multiple of DECDPUN */
-/* during many operations, so whole Units are handled and exact */
-/* accounting of digits is not needed. The correct digits value */
-/* is found by decGetDigits, which accounts for leading zeros. */
-/* This must be called before any rounding if the number of digits */
-/* is not known exactly. */
-/* */
-/* 7. The multiply-by-reciprocal 'trick' is used for partitioning */
-/* numbers up to four digits, using appropriate constants. This */
-/* is not useful for longer numbers because overflow of 32 bits */
-/* would lead to 4 multiplies, which is almost as expensive as */
-/* a divide (unless a floating-point or 64-bit multiply is */
-/* assumed to be available). */
-/* */
-/* 8. Unusual abbreviations that may be used in the commentary: */
-/* lhs -- left hand side (operand, of an operation) */
-/* lsd -- least significant digit (of coefficient) */
-/* lsu -- least significant Unit (of coefficient) */
-/* msd -- most significant digit (of coefficient) */
-/* msi -- most significant item (in an array) */
-/* msu -- most significant Unit (of coefficient) */
-/* rhs -- right hand side (operand, of an operation) */
-/* +ve -- positive */
-/* -ve -- negative */
-/* ** -- raise to the power */
-/* ------------------------------------------------------------------ */
-
-#include <stdlib.h> /* for malloc, free, etc. */
-/* #include <stdio.h> */ /* for printf [if needed] */
-#include <string.h> /* for strcpy */
-#include <ctype.h> /* for lower */
-#include "cmemory.h" /* for uprv_malloc, etc., in ICU */
-#include "decNumber.h" /* base number library */
-#include "decNumberLocal.h" /* decNumber local types, etc. */
-#include "uassert.h"
-
-/* Constants */
-/* Public lookup table used by the D2U macro */
-static const uByte d2utable[DECMAXD2U+1]=D2UTABLE;
-
-#define DECVERB 1 /* set to 1 for verbose DECCHECK */
-#define powers DECPOWERS /* old internal name */
-
-/* Local constants */
-#define DIVIDE 0x80 /* Divide operators */
-#define REMAINDER 0x40 /* .. */
-#define DIVIDEINT 0x20 /* .. */
-#define REMNEAR 0x10 /* .. */
-#define COMPARE 0x01 /* Compare operators */
-#define COMPMAX 0x02 /* .. */
-#define COMPMIN 0x03 /* .. */
-#define COMPTOTAL 0x04 /* .. */
-#define COMPNAN 0x05 /* .. [NaN processing] */
-#define COMPSIG 0x06 /* .. [signaling COMPARE] */
-#define COMPMAXMAG 0x07 /* .. */
-#define COMPMINMAG 0x08 /* .. */
-
-#define DEC_sNaN 0x40000000 /* local status: sNaN signal */
-#define BADINT (Int)0x80000000 /* most-negative Int; error indicator */
-/* Next two indicate an integer >= 10**6, and its parity (bottom bit) */
-#define BIGEVEN (Int)0x80000002
-#define BIGODD (Int)0x80000003
-
-static const Unit uarrone[1]={1}; /* Unit array of 1, used for incrementing */
-
-/* ------------------------------------------------------------------ */
-/* round-for-reround digits */
-/* ------------------------------------------------------------------ */
-#if 0
-static const uByte DECSTICKYTAB[10]={1,1,2,3,4,6,6,7,8,9}; /* used if sticky */
-#endif
-
-/* ------------------------------------------------------------------ */
-/* Powers of ten (powers[n]==10**n, 0<=n<=9) */
-/* ------------------------------------------------------------------ */
-static const uInt DECPOWERS[10]={1, 10, 100, 1000, 10000, 100000, 1000000,
- 10000000, 100000000, 1000000000};
-
-
-/* Granularity-dependent code */
-#if DECDPUN<=4
- #define eInt Int /* extended integer */
- #define ueInt uInt /* unsigned extended integer */
- /* Constant multipliers for divide-by-power-of five using reciprocal */
- /* multiply, after removing powers of 2 by shifting, and final shift */
- /* of 17 [we only need up to **4] */
- static const uInt multies[]={131073, 26215, 5243, 1049, 210};
- /* QUOT10 -- macro to return the quotient of unit u divided by 10**n */
- #define QUOT10(u, n) ((((uInt)(u)>>(n))*multies[n])>>17)
-#else
- /* For DECDPUN>4 non-ANSI-89 64-bit types are needed. */
- #if !DECUSE64
- #error decNumber.c: DECUSE64 must be 1 when DECDPUN>4
- #endif
- #define eInt Long /* extended integer */
- #define ueInt uLong /* unsigned extended integer */
-#endif
-
-/* Local routines */
-static decNumber * decAddOp(decNumber *, const decNumber *, const decNumber *,
- decContext *, uByte, uInt *);
-static Flag decBiStr(const char *, const char *, const char *);
-static uInt decCheckMath(const decNumber *, decContext *, uInt *);
-static void decApplyRound(decNumber *, decContext *, Int, uInt *);
-static Int decCompare(const decNumber *lhs, const decNumber *rhs, Flag);
-static decNumber * decCompareOp(decNumber *, const decNumber *,
- const decNumber *, decContext *,
- Flag, uInt *);
-static void decCopyFit(decNumber *, const decNumber *, decContext *,
- Int *, uInt *);
-static decNumber * decDecap(decNumber *, Int);
-static decNumber * decDivideOp(decNumber *, const decNumber *,
- const decNumber *, decContext *, Flag, uInt *);
-static decNumber * decExpOp(decNumber *, const decNumber *,
- decContext *, uInt *);
-static void decFinalize(decNumber *, decContext *, Int *, uInt *);
-static Int decGetDigits(Unit *, Int);
-static Int decGetInt(const decNumber *);
-static decNumber * decLnOp(decNumber *, const decNumber *,
- decContext *, uInt *);
-static decNumber * decMultiplyOp(decNumber *, const decNumber *,
- const decNumber *, decContext *,
- uInt *);
-static decNumber * decNaNs(decNumber *, const decNumber *,
- const decNumber *, decContext *, uInt *);
-static decNumber * decQuantizeOp(decNumber *, const decNumber *,
- const decNumber *, decContext *, Flag,
- uInt *);
-static void decReverse(Unit *, Unit *);
-static void decSetCoeff(decNumber *, decContext *, const Unit *,
- Int, Int *, uInt *);
-static void decSetMaxValue(decNumber *, decContext *);
-static void decSetOverflow(decNumber *, decContext *, uInt *);
-static void decSetSubnormal(decNumber *, decContext *, Int *, uInt *);
-static Int decShiftToLeast(Unit *, Int, Int);
-static Int decShiftToMost(Unit *, Int, Int);
-static void decStatus(decNumber *, uInt, decContext *);
-static void decToString(const decNumber *, char[], Flag);
-static decNumber * decTrim(decNumber *, decContext *, Flag, Flag, Int *);
-static Int decUnitAddSub(const Unit *, Int, const Unit *, Int, Int,
- Unit *, Int);
-static Int decUnitCompare(const Unit *, Int, const Unit *, Int, Int);
-
-#if !DECSUBSET
-/* decFinish == decFinalize when no subset arithmetic needed */
-#define decFinish(a,b,c,d) decFinalize(a,b,c,d)
-#else
-static void decFinish(decNumber *, decContext *, Int *, uInt *);
-static decNumber * decRoundOperand(const decNumber *, decContext *, uInt *);
-#endif
-
-/* Local macros */
-/* masked special-values bits */
-#define SPECIALARG (rhs->bits & DECSPECIAL)
-#define SPECIALARGS ((lhs->bits | rhs->bits) & DECSPECIAL)
-
-/* For use in ICU */
-#define malloc(a) uprv_malloc(a)
-#define free(a) uprv_free(a)
-
-/* Diagnostic macros, etc. */
-#if DECALLOC
-/* Handle malloc/free accounting. If enabled, our accountable routines */
-/* are used; otherwise the code just goes straight to the system malloc */
-/* and free routines. */
-#define malloc(a) decMalloc(a)
-#define free(a) decFree(a)
-#define DECFENCE 0x5a /* corruption detector */
-/* 'Our' malloc and free: */
-static void *decMalloc(size_t);
-static void decFree(void *);
-uInt decAllocBytes=0; /* count of bytes allocated */
-/* Note that DECALLOC code only checks for storage buffer overflow. */
-/* To check for memory leaks, the decAllocBytes variable must be */
-/* checked to be 0 at appropriate times (e.g., after the test */
-/* harness completes a set of tests). This checking may be unreliable */
-/* if the testing is done in a multi-thread environment. */
-#endif
-
-#if DECCHECK
-/* Optional checking routines. Enabling these means that decNumber */
-/* and decContext operands to operator routines are checked for */
-/* correctness. This roughly doubles the execution time of the */
-/* fastest routines (and adds 600+ bytes), so should not normally be */
-/* used in 'production'. */
-/* decCheckInexact is used to check that inexact results have a full */
-/* complement of digits (where appropriate -- this is not the case */
-/* for Quantize, for example) */
-#define DECUNRESU ((decNumber *)(void *)0xffffffff)
-#define DECUNUSED ((const decNumber *)(void *)0xffffffff)
-#define DECUNCONT ((decContext *)(void *)(0xffffffff))
-static Flag decCheckOperands(decNumber *, const decNumber *,
- const decNumber *, decContext *);
-static Flag decCheckNumber(const decNumber *);
-static void decCheckInexact(const decNumber *, decContext *);
-#endif
-
-#if DECTRACE || DECCHECK
-/* Optional trace/debugging routines (may or may not be used) */
-void decNumberShow(const decNumber *); /* displays the components of a number */
-static void decDumpAr(char, const Unit *, Int);
-#endif
-
-/* ================================================================== */
-/* Conversions */
-/* ================================================================== */
-
-/* ------------------------------------------------------------------ */
-/* from-int32 -- conversion from Int or uInt */
-/* */
-/* dn is the decNumber to receive the integer */
-/* in or uin is the integer to be converted */
-/* returns dn */
-/* */
-/* No error is possible. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberFromInt32(decNumber *dn, Int in) {
- uInt unsig;
- if (in>=0) unsig=in;
- else { /* negative (possibly BADINT) */
- if (in==BADINT) unsig=(uInt)1073741824*2; /* special case */
- else unsig=-in; /* invert */
- }
- /* in is now positive */
- uprv_decNumberFromUInt32(dn, unsig);
- if (in<0) dn->bits=DECNEG; /* sign needed */
- return dn;
- } /* decNumberFromInt32 */
-
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberFromUInt32(decNumber *dn, uInt uin) {
- Unit *up; /* work pointer */
- uprv_decNumberZero(dn); /* clean */
- if (uin==0) return dn; /* [or decGetDigits bad call] */
- for (up=dn->lsu; uin>0; up++) {
- *up=(Unit)(uin%(DECDPUNMAX+1));
- uin=uin/(DECDPUNMAX+1);
- }
- dn->digits=decGetDigits(dn->lsu, static_cast<int32_t>(up - dn->lsu));
- return dn;
- } /* decNumberFromUInt32 */
-
-/* ------------------------------------------------------------------ */
-/* to-int32 -- conversion to Int or uInt */
-/* */
-/* dn is the decNumber to convert */
-/* set is the context for reporting errors */
-/* returns the converted decNumber, or 0 if Invalid is set */
-/* */
-/* Invalid is set if the decNumber does not have exponent==0 or if */
-/* it is a NaN, Infinite, or out-of-range. */
-/* ------------------------------------------------------------------ */
-U_CAPI Int U_EXPORT2 uprv_decNumberToInt32(const decNumber *dn, decContext *set) {
- #if DECCHECK
- if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0;
- #endif
-
- /* special or too many digits, or bad exponent */
- if (dn->bits&DECSPECIAL || dn->digits>10 || dn->exponent!=0) ; /* bad */
- else { /* is a finite integer with 10 or fewer digits */
- Int d; /* work */
- const Unit *up; /* .. */
- uInt hi=0, lo; /* .. */
- up=dn->lsu; /* -> lsu */
- lo=*up; /* get 1 to 9 digits */
- #if DECDPUN>1 /* split to higher */
- hi=lo/10;
- lo=lo%10;
- #endif
- up++;
- /* collect remaining Units, if any, into hi */
- for (d=DECDPUN; d<dn->digits; up++, d+=DECDPUN) hi+=*up*powers[d-1];
- /* now low has the lsd, hi the remainder */
- if (hi>214748364 || (hi==214748364 && lo>7)) { /* out of range? */
- /* most-negative is a reprieve */
- if (dn->bits&DECNEG && hi==214748364 && lo==8) return 0x80000000;
- /* bad -- drop through */
- }
- else { /* in-range always */
- Int i=X10(hi)+lo;
- if (dn->bits&DECNEG) return -i;
- return i;
- }
- } /* integer */
- uprv_decContextSetStatus(set, DEC_Invalid_operation); /* [may not return] */
- return 0;
- } /* decNumberToInt32 */
-
-U_CAPI uInt U_EXPORT2 uprv_decNumberToUInt32(const decNumber *dn, decContext *set) {
- #if DECCHECK
- if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0;
- #endif
- /* special or too many digits, or bad exponent, or negative (<0) */
- if (dn->bits&DECSPECIAL || dn->digits>10 || dn->exponent!=0
- || (dn->bits&DECNEG && !ISZERO(dn))); /* bad */
- else { /* is a finite integer with 10 or fewer digits */
- Int d; /* work */
- const Unit *up; /* .. */
- uInt hi=0, lo; /* .. */
- up=dn->lsu; /* -> lsu */
- lo=*up; /* get 1 to 9 digits */
- #if DECDPUN>1 /* split to higher */
- hi=lo/10;
- lo=lo%10;
- #endif
- up++;
- /* collect remaining Units, if any, into hi */
- for (d=DECDPUN; d<dn->digits; up++, d+=DECDPUN) hi+=*up*powers[d-1];
-
- /* now low has the lsd, hi the remainder */
- if (hi>429496729 || (hi==429496729 && lo>5)) ; /* no reprieve possible */
- else return X10(hi)+lo;
- } /* integer */
- uprv_decContextSetStatus(set, DEC_Invalid_operation); /* [may not return] */
- return 0;
- } /* decNumberToUInt32 */
-
-/* ------------------------------------------------------------------ */
-/* to-scientific-string -- conversion to numeric string */
-/* to-engineering-string -- conversion to numeric string */
-/* */
-/* decNumberToString(dn, string); */
-/* decNumberToEngString(dn, string); */
-/* */
-/* dn is the decNumber to convert */
-/* string is the string where the result will be laid out */
-/* */
-/* string must be at least dn->digits+14 characters long */
-/* */
-/* No error is possible, and no status can be set. */
-/* ------------------------------------------------------------------ */
-U_CAPI char * U_EXPORT2 uprv_decNumberToString(const decNumber *dn, char *string){
- decToString(dn, string, 0);
- return string;
- } /* DecNumberToString */
-
-U_CAPI char * U_EXPORT2 uprv_decNumberToEngString(const decNumber *dn, char *string){
- decToString(dn, string, 1);
- return string;
- } /* DecNumberToEngString */
-
-/* ------------------------------------------------------------------ */
-/* to-number -- conversion from numeric string */
-/* */
-/* decNumberFromString -- convert string to decNumber */
-/* dn -- the number structure to fill */
-/* chars[] -- the string to convert ('\0' terminated) */
-/* set -- the context used for processing any error, */
-/* determining the maximum precision available */
-/* (set.digits), determining the maximum and minimum */
-/* exponent (set.emax and set.emin), determining if */
-/* extended values are allowed, and checking the */
-/* rounding mode if overflow occurs or rounding is */
-/* needed. */
-/* */
-/* The length of the coefficient and the size of the exponent are */
-/* checked by this routine, so the correct error (Underflow or */
-/* Overflow) can be reported or rounding applied, as necessary. */
-/* */
-/* If bad syntax is detected, the result will be a quiet NaN. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberFromString(decNumber *dn, const char chars[],
- decContext *set) {
- Int exponent=0; /* working exponent [assume 0] */
- uByte bits=0; /* working flags [assume +ve] */
- Unit *res; /* where result will be built */
- Unit resbuff[SD2U(DECBUFFER+9)];/* local buffer in case need temporary */
- /* [+9 allows for ln() constants] */
- Unit *allocres=NULL; /* -> allocated result, iff allocated */
- Int d=0; /* count of digits found in decimal part */
- const char *dotchar=NULL; /* where dot was found */
- const char *cfirst=chars; /* -> first character of decimal part */
- const char *last=NULL; /* -> last digit of decimal part */
- const char *c; /* work */
- Unit *up; /* .. */
- #if DECDPUN>1
- Int cut, out; /* .. */
- #endif
- Int residue; /* rounding residue */
- uInt status=0; /* error code */
-
- #if DECCHECK
- if (decCheckOperands(DECUNRESU, DECUNUSED, DECUNUSED, set))
- return uprv_decNumberZero(dn);
- #endif
-
- do { /* status & malloc protection */
- for (c=chars;; c++) { /* -> input character */
- if (*c>='0' && *c<='9') { /* test for Arabic digit */
- last=c;
- d++; /* count of real digits */
- continue; /* still in decimal part */
- }
- if (*c=='.' && dotchar==NULL) { /* first '.' */
- dotchar=c; /* record offset into decimal part */
- if (c==cfirst) cfirst++; /* first digit must follow */
- continue;}
- if (c==chars) { /* first in string... */
- if (*c=='-') { /* valid - sign */
- cfirst++;
- bits=DECNEG;
- continue;}
- if (*c=='+') { /* valid + sign */
- cfirst++;
- continue;}
- }
- /* *c is not a digit, or a valid +, -, or '.' */
- break;
- } /* c */
-
- if (last==NULL) { /* no digits yet */
- status=DEC_Conversion_syntax;/* assume the worst */
- if (*c=='\0') break; /* and no more to come... */
- #if DECSUBSET
- /* if subset then infinities and NaNs are not allowed */
- if (!set->extended) break; /* hopeless */
- #endif
- /* Infinities and NaNs are possible, here */
- if (dotchar!=NULL) break; /* .. unless had a dot */
- uprv_decNumberZero(dn); /* be optimistic */
- if (decBiStr(c, "infinity", "INFINITY")
- || decBiStr(c, "inf", "INF")) {
- dn->bits=bits | DECINF;
- status=0; /* is OK */
- break; /* all done */
- }
- /* a NaN expected */
- /* 2003.09.10 NaNs are now permitted to have a sign */
- dn->bits=bits | DECNAN; /* assume simple NaN */
- if (*c=='s' || *c=='S') { /* looks like an sNaN */
- c++;
- dn->bits=bits | DECSNAN;
- }
- if (*c!='n' && *c!='N') break; /* check caseless "NaN" */
- c++;
- if (*c!='a' && *c!='A') break; /* .. */
- c++;
- if (*c!='n' && *c!='N') break; /* .. */
- c++;
- /* now either nothing, or nnnn payload, expected */
- /* -> start of integer and skip leading 0s [including plain 0] */
- for (cfirst=c; *cfirst=='0';) cfirst++;
- if (*cfirst=='\0') { /* "NaN" or "sNaN", maybe with all 0s */
- status=0; /* it's good */
- break; /* .. */
- }
- /* something other than 0s; setup last and d as usual [no dots] */
- for (c=cfirst;; c++, d++) {
- if (*c<'0' || *c>'9') break; /* test for Arabic digit */
- last=c;
- }
- if (*c!='\0') break; /* not all digits */
- if (d>set->digits-1) {
- /* [NB: payload in a decNumber can be full length unless */
- /* clamped, in which case can only be digits-1] */
- if (set->clamp) break;
- if (d>set->digits) break;
- } /* too many digits? */
- /* good; drop through to convert the integer to coefficient */
- status=0; /* syntax is OK */
- bits=dn->bits; /* for copy-back */
- } /* last==NULL */
-
- else if (*c!='\0') { /* more to process... */
- /* had some digits; exponent is only valid sequence now */
- Flag nege; /* 1=negative exponent */
- const char *firstexp; /* -> first significant exponent digit */
- status=DEC_Conversion_syntax;/* assume the worst */
- if (*c!='e' && *c!='E') break;
- /* Found 'e' or 'E' -- now process explicit exponent */
- /* 1998.07.11: sign no longer required */
- nege=0;
- c++; /* to (possible) sign */
- if (*c=='-') {nege=1; c++;}
- else if (*c=='+') c++;
- if (*c=='\0') break;
-
- for (; *c=='0' && *(c+1)!='\0';) c++; /* strip insignificant zeros */
- firstexp=c; /* save exponent digit place */
- uInt uexponent = 0; /* Avoid undefined behavior on signed int overflow */
- for (; ;c++) {
- if (*c<'0' || *c>'9') break; /* not a digit */
- uexponent=X10(uexponent)+(uInt)*c-(uInt)'0';
- } /* c */
- exponent = (Int)uexponent;
- /* if not now on a '\0', *c must not be a digit */
- if (*c!='\0') break;
-
- /* (this next test must be after the syntax checks) */
- /* if it was too long the exponent may have wrapped, so check */
- /* carefully and set it to a certain overflow if wrap possible */
- if (c>=firstexp+9+1) {
- if (c>firstexp+9+1 || *firstexp>'1') exponent=DECNUMMAXE*2;
- /* [up to 1999999999 is OK, for example 1E-1000000998] */
- }
- if (nege) exponent=-exponent; /* was negative */
- status=0; /* is OK */
- } /* stuff after digits */
-
- /* Here when whole string has been inspected; syntax is good */
- /* cfirst->first digit (never dot), last->last digit (ditto) */
-
- /* strip leading zeros/dot [leave final 0 if all 0's] */
- if (*cfirst=='0') { /* [cfirst has stepped over .] */
- for (c=cfirst; c<last; c++, cfirst++) {
- if (*c=='.') continue; /* ignore dots */
- if (*c!='0') break; /* non-zero found */
- d--; /* 0 stripped */
- } /* c */
- #if DECSUBSET
- /* make a rapid exit for easy zeros if !extended */
- if (*cfirst=='0' && !set->extended) {
- uprv_decNumberZero(dn); /* clean result */
- break; /* [could be return] */
- }
- #endif
- } /* at least one leading 0 */
-
- /* Handle decimal point... */
- if (dotchar!=NULL && dotchar<last) /* non-trailing '.' found? */
- exponent -= static_cast<int32_t>(last-dotchar); /* adjust exponent */
- /* [we can now ignore the .] */
-
- /* OK, the digits string is good. Assemble in the decNumber, or in */
- /* a temporary units array if rounding is needed */
- if (d<=set->digits) res=dn->lsu; /* fits into supplied decNumber */
- else { /* rounding needed */
- Int needbytes=D2U(d)*sizeof(Unit);/* bytes needed */
- res=resbuff; /* assume use local buffer */
- if (needbytes>(Int)sizeof(resbuff)) { /* too big for local */
- allocres=(Unit *)malloc(needbytes);
- if (allocres==NULL) {status|=DEC_Insufficient_storage; break;}
- res=allocres;
- }
- }
- /* res now -> number lsu, buffer, or allocated storage for Unit array */
-
- /* Place the coefficient into the selected Unit array */
- /* [this is often 70% of the cost of this function when DECDPUN>1] */
- #if DECDPUN>1
- out=0; /* accumulator */
- up=res+D2U(d)-1; /* -> msu */
- cut=d-(up-res)*DECDPUN; /* digits in top unit */
- for (c=cfirst;; c++) { /* along the digits */
- if (*c=='.') continue; /* ignore '.' [don't decrement cut] */
- out=X10(out)+(Int)*c-(Int)'0';
- if (c==last) break; /* done [never get to trailing '.'] */
- cut--;
- if (cut>0) continue; /* more for this unit */
- *up=(Unit)out; /* write unit */
- up--; /* prepare for unit below.. */
- cut=DECDPUN; /* .. */
- out=0; /* .. */
- } /* c */
- *up=(Unit)out; /* write lsu */
-
- #else
- /* DECDPUN==1 */
- up=res; /* -> lsu */
- for (c=last; c>=cfirst; c--) { /* over each character, from least */
- if (*c=='.') continue; /* ignore . [don't step up] */
- *up=(Unit)((Int)*c-(Int)'0');
- up++;
- } /* c */
- #endif
-
- dn->bits=bits;
- dn->exponent=exponent;
- dn->digits=d;
-
- /* if not in number (too long) shorten into the number */
- if (d>set->digits) {
- residue=0;
- decSetCoeff(dn, set, res, d, &residue, &status);
- /* always check for overflow or subnormal and round as needed */
- decFinalize(dn, set, &residue, &status);
- }
- else { /* no rounding, but may still have overflow or subnormal */
- /* [these tests are just for performance; finalize repeats them] */
- if ((dn->exponent-1<set->emin-dn->digits)
- || (dn->exponent-1>set->emax-set->digits)) {
- residue=0;
- decFinalize(dn, set, &residue, &status);
- }
- }
- /* decNumberShow(dn); */
- } while(0); /* [for break] */
-
- if (allocres!=NULL) free(allocres); /* drop any storage used */
- if (status!=0) decStatus(dn, status, set);
- return dn;
- } /* decNumberFromString */
-
-/* ================================================================== */
-/* Operators */
-/* ================================================================== */
-
-/* ------------------------------------------------------------------ */
-/* decNumberAbs -- absolute value operator */
-/* */
-/* This computes C = abs(A) */
-/* */
-/* res is C, the result. C may be A */
-/* rhs is A */
-/* set is the context */
-/* */
-/* See also decNumberCopyAbs for a quiet bitwise version of this. */
-/* C must have space for set->digits digits. */
-/* ------------------------------------------------------------------ */
-/* This has the same effect as decNumberPlus unless A is negative, */
-/* in which case it has the same effect as decNumberMinus. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberAbs(decNumber *res, const decNumber *rhs,
- decContext *set) {
- decNumber dzero; /* for 0 */
- uInt status=0; /* accumulator */
-
- #if DECCHECK
- if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
- #endif
-
- uprv_decNumberZero(&dzero); /* set 0 */
- dzero.exponent=rhs->exponent; /* [no coefficient expansion] */
- decAddOp(res, &dzero, rhs, set, (uByte)(rhs->bits & DECNEG), &status);
- if (status!=0) decStatus(res, status, set);
- #if DECCHECK
- decCheckInexact(res, set);
- #endif
- return res;
- } /* decNumberAbs */
-
-/* ------------------------------------------------------------------ */
-/* decNumberAdd -- add two Numbers */
-/* */
-/* This computes C = A + B */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=X+X) */
-/* lhs is A */
-/* rhs is B */
-/* set is the context */
-/* */
-/* C must have space for set->digits digits. */
-/* ------------------------------------------------------------------ */
-/* This just calls the routine shared with Subtract */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberAdd(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- uInt status=0; /* accumulator */
- decAddOp(res, lhs, rhs, set, 0, &status);
- if (status!=0) decStatus(res, status, set);
- #if DECCHECK
- decCheckInexact(res, set);
- #endif
- return res;
- } /* decNumberAdd */
-
-/* ------------------------------------------------------------------ */
-/* decNumberAnd -- AND two Numbers, digitwise */
-/* */
-/* This computes C = A & B */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=X&X) */
-/* lhs is A */
-/* rhs is B */
-/* set is the context (used for result length and error report) */
-/* */
-/* C must have space for set->digits digits. */
-/* */
-/* Logical function restrictions apply (see above); a NaN is */
-/* returned with Invalid_operation if a restriction is violated. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberAnd(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- const Unit *ua, *ub; /* -> operands */
- const Unit *msua, *msub; /* -> operand msus */
- Unit *uc, *msuc; /* -> result and its msu */
- Int msudigs; /* digits in res msu */
- #if DECCHECK
- if (decCheckOperands(res, lhs, rhs, set)) return res;
- #endif
-
- if (lhs->exponent!=0 || decNumberIsSpecial(lhs) || decNumberIsNegative(lhs)
- || rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) {
- decStatus(res, DEC_Invalid_operation, set);
- return res;
- }
-
- /* operands are valid */
- ua=lhs->lsu; /* bottom-up */
- ub=rhs->lsu; /* .. */
- uc=res->lsu; /* .. */
- msua=ua+D2U(lhs->digits)-1; /* -> msu of lhs */
- msub=ub+D2U(rhs->digits)-1; /* -> msu of rhs */
- msuc=uc+D2U(set->digits)-1; /* -> msu of result */
- msudigs=MSUDIGITS(set->digits); /* [faster than remainder] */
- for (; uc<=msuc; ua++, ub++, uc++) { /* Unit loop */
- Unit a, b; /* extract units */
- if (ua>msua) a=0;
- else a=*ua;
- if (ub>msub) b=0;
- else b=*ub;
- *uc=0; /* can now write back */
- if (a|b) { /* maybe 1 bits to examine */
- Int i, j;
- *uc=0; /* can now write back */
- /* This loop could be unrolled and/or use BIN2BCD tables */
- for (i=0; i<DECDPUN; i++) {
- if (a&b&1) *uc=*uc+(Unit)powers[i]; /* effect AND */
- j=a%10;
- a=a/10;
- j|=b%10;
- b=b/10;
- if (j>1) {
- decStatus(res, DEC_Invalid_operation, set);
- return res;
- }
- if (uc==msuc && i==msudigs-1) break; /* just did final digit */
- } /* each digit */
- } /* both OK */
- } /* each unit */
- /* [here uc-1 is the msu of the result] */
- res->digits=decGetDigits(res->lsu, static_cast<int32_t>(uc - res->lsu));
- res->exponent=0; /* integer */
- res->bits=0; /* sign=0 */
- return res; /* [no status to set] */
- } /* decNumberAnd */
-
-/* ------------------------------------------------------------------ */
-/* decNumberCompare -- compare two Numbers */
-/* */
-/* This computes C = A ? B */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
-/* lhs is A */
-/* rhs is B */
-/* set is the context */
-/* */
-/* C must have space for one digit (or NaN). */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberCompare(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- uInt status=0; /* accumulator */
- decCompareOp(res, lhs, rhs, set, COMPARE, &status);
- if (status!=0) decStatus(res, status, set);
- return res;
- } /* decNumberCompare */
-
-/* ------------------------------------------------------------------ */
-/* decNumberCompareSignal -- compare, signalling on all NaNs */
-/* */
-/* This computes C = A ? B */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
-/* lhs is A */
-/* rhs is B */
-/* set is the context */
-/* */
-/* C must have space for one digit (or NaN). */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberCompareSignal(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- uInt status=0; /* accumulator */
- decCompareOp(res, lhs, rhs, set, COMPSIG, &status);
- if (status!=0) decStatus(res, status, set);
- return res;
- } /* decNumberCompareSignal */
-
-/* ------------------------------------------------------------------ */
-/* decNumberCompareTotal -- compare two Numbers, using total ordering */
-/* */
-/* This computes C = A ? B, under total ordering */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
-/* lhs is A */
-/* rhs is B */
-/* set is the context */
-/* */
-/* C must have space for one digit; the result will always be one of */
-/* -1, 0, or 1. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberCompareTotal(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- uInt status=0; /* accumulator */
- decCompareOp(res, lhs, rhs, set, COMPTOTAL, &status);
- if (status!=0) decStatus(res, status, set);
- return res;
- } /* decNumberCompareTotal */
-
-/* ------------------------------------------------------------------ */
-/* decNumberCompareTotalMag -- compare, total ordering of magnitudes */
-/* */
-/* This computes C = |A| ? |B|, under total ordering */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
-/* lhs is A */
-/* rhs is B */
-/* set is the context */
-/* */
-/* C must have space for one digit; the result will always be one of */
-/* -1, 0, or 1. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberCompareTotalMag(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- uInt status=0; /* accumulator */
- uInt needbytes; /* for space calculations */
- decNumber bufa[D2N(DECBUFFER+1)];/* +1 in case DECBUFFER=0 */
- decNumber *allocbufa=NULL; /* -> allocated bufa, iff allocated */
- decNumber bufb[D2N(DECBUFFER+1)];
- decNumber *allocbufb=NULL; /* -> allocated bufb, iff allocated */
- decNumber *a, *b; /* temporary pointers */
-
- #if DECCHECK
- if (decCheckOperands(res, lhs, rhs, set)) return res;
- #endif
-
- do { /* protect allocated storage */
- /* if either is negative, take a copy and absolute */
- if (decNumberIsNegative(lhs)) { /* lhs<0 */
- a=bufa;
- needbytes=sizeof(decNumber)+(D2U(lhs->digits)-1)*sizeof(Unit);
- if (needbytes>sizeof(bufa)) { /* need malloc space */
- allocbufa=(decNumber *)malloc(needbytes);
- if (allocbufa==NULL) { /* hopeless -- abandon */
- status|=DEC_Insufficient_storage;
- break;}
- a=allocbufa; /* use the allocated space */
- }
- uprv_decNumberCopy(a, lhs); /* copy content */
- a->bits&=~DECNEG; /* .. and clear the sign */
- lhs=a; /* use copy from here on */
- }
- if (decNumberIsNegative(rhs)) { /* rhs<0 */
- b=bufb;
- needbytes=sizeof(decNumber)+(D2U(rhs->digits)-1)*sizeof(Unit);
- if (needbytes>sizeof(bufb)) { /* need malloc space */
- allocbufb=(decNumber *)malloc(needbytes);
- if (allocbufb==NULL) { /* hopeless -- abandon */
- status|=DEC_Insufficient_storage;
- break;}
- b=allocbufb; /* use the allocated space */
- }
- uprv_decNumberCopy(b, rhs); /* copy content */
- b->bits&=~DECNEG; /* .. and clear the sign */
- rhs=b; /* use copy from here on */
- }
- decCompareOp(res, lhs, rhs, set, COMPTOTAL, &status);
- } while(0); /* end protected */
-
- if (allocbufa!=NULL) free(allocbufa); /* drop any storage used */
- if (allocbufb!=NULL) free(allocbufb); /* .. */
- if (status!=0) decStatus(res, status, set);
- return res;
- } /* decNumberCompareTotalMag */
-
-/* ------------------------------------------------------------------ */
-/* decNumberDivide -- divide one number by another */
-/* */
-/* This computes C = A / B */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=X/X) */
-/* lhs is A */
-/* rhs is B */
-/* set is the context */
-/* */
-/* C must have space for set->digits digits. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberDivide(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- uInt status=0; /* accumulator */
- decDivideOp(res, lhs, rhs, set, DIVIDE, &status);
- if (status!=0) decStatus(res, status, set);
- #if DECCHECK
- decCheckInexact(res, set);
- #endif
- return res;
- } /* decNumberDivide */
-
-/* ------------------------------------------------------------------ */
-/* decNumberDivideInteger -- divide and return integer quotient */
-/* */
-/* This computes C = A # B, where # is the integer divide operator */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=X#X) */
-/* lhs is A */
-/* rhs is B */
-/* set is the context */
-/* */
-/* C must have space for set->digits digits. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberDivideInteger(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- uInt status=0; /* accumulator */
- decDivideOp(res, lhs, rhs, set, DIVIDEINT, &status);
- if (status!=0) decStatus(res, status, set);
- return res;
- } /* decNumberDivideInteger */
-
-/* ------------------------------------------------------------------ */
-/* decNumberExp -- exponentiation */
-/* */
-/* This computes C = exp(A) */
-/* */
-/* res is C, the result. C may be A */
-/* rhs is A */
-/* set is the context; note that rounding mode has no effect */
-/* */
-/* C must have space for set->digits digits. */
-/* */
-/* Mathematical function restrictions apply (see above); a NaN is */
-/* returned with Invalid_operation if a restriction is violated. */
-/* */
-/* Finite results will always be full precision and Inexact, except */
-/* when A is a zero or -Infinity (giving 1 or 0 respectively). */
-/* */
-/* An Inexact result is rounded using DEC_ROUND_HALF_EVEN; it will */
-/* almost always be correctly rounded, but may be up to 1 ulp in */
-/* error in rare cases. */
-/* ------------------------------------------------------------------ */
-/* This is a wrapper for decExpOp which can handle the slightly wider */
-/* (double) range needed by Ln (which has to be able to calculate */
-/* exp(-a) where a can be the tiniest number (Ntiny). */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberExp(decNumber *res, const decNumber *rhs,
- decContext *set) {
- uInt status=0; /* accumulator */
- #if DECSUBSET
- decNumber *allocrhs=NULL; /* non-NULL if rounded rhs allocated */
- #endif
-
- #if DECCHECK
- if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
- #endif
-
- /* Check restrictions; these restrictions ensure that if h=8 (see */
- /* decExpOp) then the result will either overflow or underflow to 0. */
- /* Other math functions restrict the input range, too, for inverses. */
- /* If not violated then carry out the operation. */
- if (!decCheckMath(rhs, set, &status)) do { /* protect allocation */
- #if DECSUBSET
- if (!set->extended) {
- /* reduce operand and set lostDigits status, as needed */
- if (rhs->digits>set->digits) {
- allocrhs=decRoundOperand(rhs, set, &status);
- if (allocrhs==NULL) break;
- rhs=allocrhs;
- }
- }
- #endif
- decExpOp(res, rhs, set, &status);
- } while(0); /* end protected */
-
- #if DECSUBSET
- if (allocrhs !=NULL) free(allocrhs); /* drop any storage used */
- #endif
- /* apply significant status */
- if (status!=0) decStatus(res, status, set);
- #if DECCHECK
- decCheckInexact(res, set);
- #endif
- return res;
- } /* decNumberExp */
-
-/* ------------------------------------------------------------------ */
-/* decNumberFMA -- fused multiply add */
-/* */
-/* This computes D = (A * B) + C with only one rounding */
-/* */
-/* res is D, the result. D may be A or B or C (e.g., X=FMA(X,X,X)) */
-/* lhs is A */
-/* rhs is B */
-/* fhs is C [far hand side] */
-/* set is the context */
-/* */
-/* Mathematical function restrictions apply (see above); a NaN is */
-/* returned with Invalid_operation if a restriction is violated. */
-/* */
-/* C must have space for set->digits digits. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberFMA(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, const decNumber *fhs,
- decContext *set) {
- uInt status=0; /* accumulator */
- decContext dcmul; /* context for the multiplication */
- uInt needbytes; /* for space calculations */
- decNumber bufa[D2N(DECBUFFER*2+1)];
- decNumber *allocbufa=NULL; /* -> allocated bufa, iff allocated */
- decNumber *acc; /* accumulator pointer */
- decNumber dzero; /* work */
-
- #if DECCHECK
- if (decCheckOperands(res, lhs, rhs, set)) return res;
- if (decCheckOperands(res, fhs, DECUNUSED, set)) return res;
- #endif
-
- do { /* protect allocated storage */
- #if DECSUBSET
- if (!set->extended) { /* [undefined if subset] */
- status|=DEC_Invalid_operation;
- break;}
- #endif
- /* Check math restrictions [these ensure no overflow or underflow] */
- if ((!decNumberIsSpecial(lhs) && decCheckMath(lhs, set, &status))
- || (!decNumberIsSpecial(rhs) && decCheckMath(rhs, set, &status))
- || (!decNumberIsSpecial(fhs) && decCheckMath(fhs, set, &status))) break;
- /* set up context for multiply */
- dcmul=*set;
- dcmul.digits=lhs->digits+rhs->digits; /* just enough */
- /* [The above may be an over-estimate for subset arithmetic, but that's OK] */
- dcmul.emax=DEC_MAX_EMAX; /* effectively unbounded .. */
- dcmul.emin=DEC_MIN_EMIN; /* [thanks to Math restrictions] */
- /* set up decNumber space to receive the result of the multiply */
- acc=bufa; /* may fit */
- needbytes=sizeof(decNumber)+(D2U(dcmul.digits)-1)*sizeof(Unit);
- if (needbytes>sizeof(bufa)) { /* need malloc space */
- allocbufa=(decNumber *)malloc(needbytes);
- if (allocbufa==NULL) { /* hopeless -- abandon */
- status|=DEC_Insufficient_storage;
- break;}
- acc=allocbufa; /* use the allocated space */
- }
- /* multiply with extended range and necessary precision */
- /*printf("emin=%ld\n", dcmul.emin); */
- decMultiplyOp(acc, lhs, rhs, &dcmul, &status);
- /* Only Invalid operation (from sNaN or Inf * 0) is possible in */
- /* status; if either is seen than ignore fhs (in case it is */
- /* another sNaN) and set acc to NaN unless we had an sNaN */
- /* [decMultiplyOp leaves that to caller] */
- /* Note sNaN has to go through addOp to shorten payload if */
- /* necessary */
- if ((status&DEC_Invalid_operation)!=0) {
- if (!(status&DEC_sNaN)) { /* but be true invalid */
- uprv_decNumberZero(res); /* acc not yet set */
- res->bits=DECNAN;
- break;
- }
- uprv_decNumberZero(&dzero); /* make 0 (any non-NaN would do) */
- fhs=&dzero; /* use that */
- }
- #if DECCHECK
- else { /* multiply was OK */
- if (status!=0) printf("Status=%08lx after FMA multiply\n", (LI)status);
- }
- #endif
- /* add the third operand and result -> res, and all is done */
- decAddOp(res, acc, fhs, set, 0, &status);
- } while(0); /* end protected */
-
- if (allocbufa!=NULL) free(allocbufa); /* drop any storage used */
- if (status!=0) decStatus(res, status, set);
- #if DECCHECK
- decCheckInexact(res, set);
- #endif
- return res;
- } /* decNumberFMA */
-
-/* ------------------------------------------------------------------ */
-/* decNumberInvert -- invert a Number, digitwise */
-/* */
-/* This computes C = ~A */
-/* */
-/* res is C, the result. C may be A (e.g., X=~X) */
-/* rhs is A */
-/* set is the context (used for result length and error report) */
-/* */
-/* C must have space for set->digits digits. */
-/* */
-/* Logical function restrictions apply (see above); a NaN is */
-/* returned with Invalid_operation if a restriction is violated. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberInvert(decNumber *res, const decNumber *rhs,
- decContext *set) {
- const Unit *ua, *msua; /* -> operand and its msu */
- Unit *uc, *msuc; /* -> result and its msu */
- Int msudigs; /* digits in res msu */
- #if DECCHECK
- if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
- #endif
-
- if (rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) {
- decStatus(res, DEC_Invalid_operation, set);
- return res;
- }
- /* operand is valid */
- ua=rhs->lsu; /* bottom-up */
- uc=res->lsu; /* .. */
- msua=ua+D2U(rhs->digits)-1; /* -> msu of rhs */
- msuc=uc+D2U(set->digits)-1; /* -> msu of result */
- msudigs=MSUDIGITS(set->digits); /* [faster than remainder] */
- for (; uc<=msuc; ua++, uc++) { /* Unit loop */
- Unit a; /* extract unit */
- Int i, j; /* work */
- if (ua>msua) a=0;
- else a=*ua;
- *uc=0; /* can now write back */
- /* always need to examine all bits in rhs */
- /* This loop could be unrolled and/or use BIN2BCD tables */
- for (i=0; i<DECDPUN; i++) {
- if ((~a)&1) *uc=*uc+(Unit)powers[i]; /* effect INVERT */
- j=a%10;
- a=a/10;
- if (j>1) {
- decStatus(res, DEC_Invalid_operation, set);
- return res;
- }
- if (uc==msuc && i==msudigs-1) break; /* just did final digit */
- } /* each digit */
- } /* each unit */
- /* [here uc-1 is the msu of the result] */
- res->digits=decGetDigits(res->lsu, static_cast<int32_t>(uc - res->lsu));
- res->exponent=0; /* integer */
- res->bits=0; /* sign=0 */
- return res; /* [no status to set] */
- } /* decNumberInvert */
-
-/* ------------------------------------------------------------------ */
-/* decNumberLn -- natural logarithm */
-/* */
-/* This computes C = ln(A) */
-/* */
-/* res is C, the result. C may be A */
-/* rhs is A */
-/* set is the context; note that rounding mode has no effect */
-/* */
-/* C must have space for set->digits digits. */
-/* */
-/* Notable cases: */
-/* A<0 -> Invalid */
-/* A=0 -> -Infinity (Exact) */
-/* A=+Infinity -> +Infinity (Exact) */
-/* A=1 exactly -> 0 (Exact) */
-/* */
-/* Mathematical function restrictions apply (see above); a NaN is */
-/* returned with Invalid_operation if a restriction is violated. */
-/* */
-/* An Inexact result is rounded using DEC_ROUND_HALF_EVEN; it will */
-/* almost always be correctly rounded, but may be up to 1 ulp in */
-/* error in rare cases. */
-/* ------------------------------------------------------------------ */
-/* This is a wrapper for decLnOp which can handle the slightly wider */
-/* (+11) range needed by Ln, Log10, etc. (which may have to be able */
-/* to calculate at p+e+2). */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberLn(decNumber *res, const decNumber *rhs,
- decContext *set) {
- uInt status=0; /* accumulator */
- #if DECSUBSET
- decNumber *allocrhs=NULL; /* non-NULL if rounded rhs allocated */
- #endif
-
- #if DECCHECK
- if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
- #endif
-
- /* Check restrictions; this is a math function; if not violated */
- /* then carry out the operation. */
- if (!decCheckMath(rhs, set, &status)) do { /* protect allocation */
- #if DECSUBSET
- if (!set->extended) {
- /* reduce operand and set lostDigits status, as needed */
- if (rhs->digits>set->digits) {
- allocrhs=decRoundOperand(rhs, set, &status);
- if (allocrhs==NULL) break;
- rhs=allocrhs;
- }
- /* special check in subset for rhs=0 */
- if (ISZERO(rhs)) { /* +/- zeros -> error */
- status|=DEC_Invalid_operation;
- break;}
- } /* extended=0 */
- #endif
- decLnOp(res, rhs, set, &status);
- } while(0); /* end protected */
-
- #if DECSUBSET
- if (allocrhs !=NULL) free(allocrhs); /* drop any storage used */
- #endif
- /* apply significant status */
- if (status!=0) decStatus(res, status, set);
- #if DECCHECK
- decCheckInexact(res, set);
- #endif
- return res;
- } /* decNumberLn */
-
-/* ------------------------------------------------------------------ */
-/* decNumberLogB - get adjusted exponent, by 754 rules */
-/* */
-/* This computes C = adjustedexponent(A) */
-/* */
-/* res is C, the result. C may be A */
-/* rhs is A */
-/* set is the context, used only for digits and status */
-/* */
-/* C must have space for 10 digits (A might have 10**9 digits and */
-/* an exponent of +999999999, or one digit and an exponent of */
-/* -1999999999). */
-/* */
-/* This returns the adjusted exponent of A after (in theory) padding */
-/* with zeros on the right to set->digits digits while keeping the */
-/* same value. The exponent is not limited by emin/emax. */
-/* */
-/* Notable cases: */
-/* A<0 -> Use |A| */
-/* A=0 -> -Infinity (Division by zero) */
-/* A=Infinite -> +Infinity (Exact) */
-/* A=1 exactly -> 0 (Exact) */
-/* NaNs are propagated as usual */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberLogB(decNumber *res, const decNumber *rhs,
- decContext *set) {
- uInt status=0; /* accumulator */
-
- #if DECCHECK
- if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
- #endif
-
- /* NaNs as usual; Infinities return +Infinity; 0->oops */
- if (decNumberIsNaN(rhs)) decNaNs(res, rhs, NULL, set, &status);
- else if (decNumberIsInfinite(rhs)) uprv_decNumberCopyAbs(res, rhs);
- else if (decNumberIsZero(rhs)) {
- uprv_decNumberZero(res); /* prepare for Infinity */
- res->bits=DECNEG|DECINF; /* -Infinity */
- status|=DEC_Division_by_zero; /* as per 754 */
- }
- else { /* finite non-zero */
- Int ae=rhs->exponent+rhs->digits-1; /* adjusted exponent */
- uprv_decNumberFromInt32(res, ae); /* lay it out */
- }
-
- if (status!=0) decStatus(res, status, set);
- return res;
- } /* decNumberLogB */
-
-/* ------------------------------------------------------------------ */
-/* decNumberLog10 -- logarithm in base 10 */
-/* */
-/* This computes C = log10(A) */
-/* */
-/* res is C, the result. C may be A */
-/* rhs is A */
-/* set is the context; note that rounding mode has no effect */
-/* */
-/* C must have space for set->digits digits. */
-/* */
-/* Notable cases: */
-/* A<0 -> Invalid */
-/* A=0 -> -Infinity (Exact) */
-/* A=+Infinity -> +Infinity (Exact) */
-/* A=10**n (if n is an integer) -> n (Exact) */
-/* */
-/* Mathematical function restrictions apply (see above); a NaN is */
-/* returned with Invalid_operation if a restriction is violated. */
-/* */
-/* An Inexact result is rounded using DEC_ROUND_HALF_EVEN; it will */
-/* almost always be correctly rounded, but may be up to 1 ulp in */
-/* error in rare cases. */
-/* ------------------------------------------------------------------ */
-/* This calculates ln(A)/ln(10) using appropriate precision. For */
-/* ln(A) this is the max(p, rhs->digits + t) + 3, where p is the */
-/* requested digits and t is the number of digits in the exponent */
-/* (maximum 6). For ln(10) it is p + 3; this is often handled by the */
-/* fastpath in decLnOp. The final division is done to the requested */
-/* precision. */
-/* ------------------------------------------------------------------ */
-#if defined(__clang__) || U_GCC_MAJOR_MINOR >= 406
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Warray-bounds"
-#endif
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberLog10(decNumber *res, const decNumber *rhs,
- decContext *set) {
- uInt status=0, ignore=0; /* status accumulators */
- uInt needbytes; /* for space calculations */
- Int p; /* working precision */
- Int t; /* digits in exponent of A */
-
- /* buffers for a and b working decimals */
- /* (adjustment calculator, same size) */
- decNumber bufa[D2N(DECBUFFER+2)];
- decNumber *allocbufa=NULL; /* -> allocated bufa, iff allocated */
- decNumber *a=bufa; /* temporary a */
- decNumber bufb[D2N(DECBUFFER+2)];
- decNumber *allocbufb=NULL; /* -> allocated bufb, iff allocated */
- decNumber *b=bufb; /* temporary b */
- decNumber bufw[D2N(10)]; /* working 2-10 digit number */
- decNumber *w=bufw; /* .. */
- #if DECSUBSET
- decNumber *allocrhs=NULL; /* non-NULL if rounded rhs allocated */
- #endif
-
- decContext aset; /* working context */
-
- #if DECCHECK
- if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
- #endif
-
- /* Check restrictions; this is a math function; if not violated */
- /* then carry out the operation. */
- if (!decCheckMath(rhs, set, &status)) do { /* protect malloc */
- #if DECSUBSET
- if (!set->extended) {
- /* reduce operand and set lostDigits status, as needed */
- if (rhs->digits>set->digits) {
- allocrhs=decRoundOperand(rhs, set, &status);
- if (allocrhs==NULL) break;
- rhs=allocrhs;
- }
- /* special check in subset for rhs=0 */
- if (ISZERO(rhs)) { /* +/- zeros -> error */
- status|=DEC_Invalid_operation;
- break;}
- } /* extended=0 */
- #endif
-
- uprv_decContextDefault(&aset, DEC_INIT_DECIMAL64); /* clean context */
-
- /* handle exact powers of 10; only check if +ve finite */
- if (!(rhs->bits&(DECNEG|DECSPECIAL)) && !ISZERO(rhs)) {
- Int residue=0; /* (no residue) */
- uInt copystat=0; /* clean status */
-
- /* round to a single digit... */
- aset.digits=1;
- decCopyFit(w, rhs, &aset, &residue, &copystat); /* copy & shorten */
- /* if exact and the digit is 1, rhs is a power of 10 */
- if (!(copystat&DEC_Inexact) && w->lsu[0]==1) {
- /* the exponent, conveniently, is the power of 10; making */
- /* this the result needs a little care as it might not fit, */
- /* so first convert it into the working number, and then move */
- /* to res */
- uprv_decNumberFromInt32(w, w->exponent);
- residue=0;
- decCopyFit(res, w, set, &residue, &status); /* copy & round */
- decFinish(res, set, &residue, &status); /* cleanup/set flags */
- break;
- } /* not a power of 10 */
- } /* not a candidate for exact */
-
- /* simplify the information-content calculation to use 'total */
- /* number of digits in a, including exponent' as compared to the */
- /* requested digits, as increasing this will only rarely cost an */
- /* iteration in ln(a) anyway */
- t=6; /* it can never be >6 */
-
- /* allocate space when needed... */
- p=(rhs->digits+t>set->digits?rhs->digits+t:set->digits)+3;
- needbytes=sizeof(decNumber)+(D2U(p)-1)*sizeof(Unit);
- if (needbytes>sizeof(bufa)) { /* need malloc space */
- allocbufa=(decNumber *)malloc(needbytes);
- if (allocbufa==NULL) { /* hopeless -- abandon */
- status|=DEC_Insufficient_storage;
- break;}
- a=allocbufa; /* use the allocated space */
- }
- aset.digits=p; /* as calculated */
- aset.emax=DEC_MAX_MATH; /* usual bounds */
- aset.emin=-DEC_MAX_MATH; /* .. */
- aset.clamp=0; /* and no concrete format */
- decLnOp(a, rhs, &aset, &status); /* a=ln(rhs) */
-
- /* skip the division if the result so far is infinite, NaN, or */
- /* zero, or there was an error; note NaN from sNaN needs copy */
- if (status&DEC_NaNs && !(status&DEC_sNaN)) break;
- if (a->bits&DECSPECIAL || ISZERO(a)) {
- uprv_decNumberCopy(res, a); /* [will fit] */
- break;}
-
- /* for ln(10) an extra 3 digits of precision are needed */
- p=set->digits+3;
- needbytes=sizeof(decNumber)+(D2U(p)-1)*sizeof(Unit);
- if (needbytes>sizeof(bufb)) { /* need malloc space */
- allocbufb=(decNumber *)malloc(needbytes);
- if (allocbufb==NULL) { /* hopeless -- abandon */
- status|=DEC_Insufficient_storage;
- break;}
- b=allocbufb; /* use the allocated space */
- }
- uprv_decNumberZero(w); /* set up 10... */
- #if DECDPUN==1
- w->lsu[1]=1; w->lsu[0]=0; /* .. */
- #else
- w->lsu[0]=10; /* .. */
- #endif
- w->digits=2; /* .. */
-
- aset.digits=p;
- decLnOp(b, w, &aset, &ignore); /* b=ln(10) */
-
- aset.digits=set->digits; /* for final divide */
- decDivideOp(res, a, b, &aset, DIVIDE, &status); /* into result */
- } while(0); /* [for break] */
-
- if (allocbufa!=NULL) free(allocbufa); /* drop any storage used */
- if (allocbufb!=NULL) free(allocbufb); /* .. */
- #if DECSUBSET
- if (allocrhs !=NULL) free(allocrhs); /* .. */
- #endif
- /* apply significant status */
- if (status!=0) decStatus(res, status, set);
- #if DECCHECK
- decCheckInexact(res, set);
- #endif
- return res;
- } /* decNumberLog10 */
-#if defined(__clang__) || U_GCC_MAJOR_MINOR >= 406
-#pragma GCC diagnostic pop
-#endif
-
-/* ------------------------------------------------------------------ */
-/* decNumberMax -- compare two Numbers and return the maximum */
-/* */
-/* This computes C = A ? B, returning the maximum by 754 rules */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
-/* lhs is A */
-/* rhs is B */
-/* set is the context */
-/* */
-/* C must have space for set->digits digits. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberMax(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- uInt status=0; /* accumulator */
- decCompareOp(res, lhs, rhs, set, COMPMAX, &status);
- if (status!=0) decStatus(res, status, set);
- #if DECCHECK
- decCheckInexact(res, set);
- #endif
- return res;
- } /* decNumberMax */
-
-/* ------------------------------------------------------------------ */
-/* decNumberMaxMag -- compare and return the maximum by magnitude */
-/* */
-/* This computes C = A ? B, returning the maximum by 754 rules */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
-/* lhs is A */
-/* rhs is B */
-/* set is the context */
-/* */
-/* C must have space for set->digits digits. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberMaxMag(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- uInt status=0; /* accumulator */
- decCompareOp(res, lhs, rhs, set, COMPMAXMAG, &status);
- if (status!=0) decStatus(res, status, set);
- #if DECCHECK
- decCheckInexact(res, set);
- #endif
- return res;
- } /* decNumberMaxMag */
-
-/* ------------------------------------------------------------------ */
-/* decNumberMin -- compare two Numbers and return the minimum */
-/* */
-/* This computes C = A ? B, returning the minimum by 754 rules */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
-/* lhs is A */
-/* rhs is B */
-/* set is the context */
-/* */
-/* C must have space for set->digits digits. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberMin(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- uInt status=0; /* accumulator */
- decCompareOp(res, lhs, rhs, set, COMPMIN, &status);
- if (status!=0) decStatus(res, status, set);
- #if DECCHECK
- decCheckInexact(res, set);
- #endif
- return res;
- } /* decNumberMin */
-
-/* ------------------------------------------------------------------ */
-/* decNumberMinMag -- compare and return the minimum by magnitude */
-/* */
-/* This computes C = A ? B, returning the minimum by 754 rules */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
-/* lhs is A */
-/* rhs is B */
-/* set is the context */
-/* */
-/* C must have space for set->digits digits. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberMinMag(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- uInt status=0; /* accumulator */
- decCompareOp(res, lhs, rhs, set, COMPMINMAG, &status);
- if (status!=0) decStatus(res, status, set);
- #if DECCHECK
- decCheckInexact(res, set);
- #endif
- return res;
- } /* decNumberMinMag */
-
-/* ------------------------------------------------------------------ */
-/* decNumberMinus -- prefix minus operator */
-/* */
-/* This computes C = 0 - A */
-/* */
-/* res is C, the result. C may be A */
-/* rhs is A */
-/* set is the context */
-/* */
-/* See also decNumberCopyNegate for a quiet bitwise version of this. */
-/* C must have space for set->digits digits. */
-/* ------------------------------------------------------------------ */
-/* Simply use AddOp for the subtract, which will do the necessary. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberMinus(decNumber *res, const decNumber *rhs,
- decContext *set) {
- decNumber dzero;
- uInt status=0; /* accumulator */
-
- #if DECCHECK
- if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
- #endif
-
- uprv_decNumberZero(&dzero); /* make 0 */
- dzero.exponent=rhs->exponent; /* [no coefficient expansion] */
- decAddOp(res, &dzero, rhs, set, DECNEG, &status);
- if (status!=0) decStatus(res, status, set);
- #if DECCHECK
- decCheckInexact(res, set);
- #endif
- return res;
- } /* decNumberMinus */
-
-/* ------------------------------------------------------------------ */
-/* decNumberNextMinus -- next towards -Infinity */
-/* */
-/* This computes C = A - infinitesimal, rounded towards -Infinity */
-/* */
-/* res is C, the result. C may be A */
-/* rhs is A */
-/* set is the context */
-/* */
-/* This is a generalization of 754 NextDown. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberNextMinus(decNumber *res, const decNumber *rhs,
- decContext *set) {
- decNumber dtiny; /* constant */
- decContext workset=*set; /* work */
- uInt status=0; /* accumulator */
- #if DECCHECK
- if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
- #endif
-
- /* +Infinity is the special case */
- if ((rhs->bits&(DECINF|DECNEG))==DECINF) {
- decSetMaxValue(res, set); /* is +ve */
- /* there is no status to set */
- return res;
- }
- uprv_decNumberZero(&dtiny); /* start with 0 */
- dtiny.lsu[0]=1; /* make number that is .. */
- dtiny.exponent=DEC_MIN_EMIN-1; /* .. smaller than tiniest */
- workset.round=DEC_ROUND_FLOOR;
- decAddOp(res, rhs, &dtiny, &workset, DECNEG, &status);
- status&=DEC_Invalid_operation|DEC_sNaN; /* only sNaN Invalid please */
- if (status!=0) decStatus(res, status, set);
- return res;
- } /* decNumberNextMinus */
-
-/* ------------------------------------------------------------------ */
-/* decNumberNextPlus -- next towards +Infinity */
-/* */
-/* This computes C = A + infinitesimal, rounded towards +Infinity */
-/* */
-/* res is C, the result. C may be A */
-/* rhs is A */
-/* set is the context */
-/* */
-/* This is a generalization of 754 NextUp. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberNextPlus(decNumber *res, const decNumber *rhs,
- decContext *set) {
- decNumber dtiny; /* constant */
- decContext workset=*set; /* work */
- uInt status=0; /* accumulator */
- #if DECCHECK
- if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
- #endif
-
- /* -Infinity is the special case */
- if ((rhs->bits&(DECINF|DECNEG))==(DECINF|DECNEG)) {
- decSetMaxValue(res, set);
- res->bits=DECNEG; /* negative */
- /* there is no status to set */
- return res;
- }
- uprv_decNumberZero(&dtiny); /* start with 0 */
- dtiny.lsu[0]=1; /* make number that is .. */
- dtiny.exponent=DEC_MIN_EMIN-1; /* .. smaller than tiniest */
- workset.round=DEC_ROUND_CEILING;
- decAddOp(res, rhs, &dtiny, &workset, 0, &status);
- status&=DEC_Invalid_operation|DEC_sNaN; /* only sNaN Invalid please */
- if (status!=0) decStatus(res, status, set);
- return res;
- } /* decNumberNextPlus */
-
-/* ------------------------------------------------------------------ */
-/* decNumberNextToward -- next towards rhs */
-/* */
-/* This computes C = A +/- infinitesimal, rounded towards */
-/* +/-Infinity in the direction of B, as per 754-1985 nextafter */
-/* modified during revision but dropped from 754-2008. */
-/* */
-/* res is C, the result. C may be A or B. */
-/* lhs is A */
-/* rhs is B */
-/* set is the context */
-/* */
-/* This is a generalization of 754-1985 NextAfter. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberNextToward(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- decNumber dtiny; /* constant */
- decContext workset=*set; /* work */
- Int result; /* .. */
- uInt status=0; /* accumulator */
- #if DECCHECK
- if (decCheckOperands(res, lhs, rhs, set)) return res;
- #endif
-
- if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs)) {
- decNaNs(res, lhs, rhs, set, &status);
- }
- else { /* Is numeric, so no chance of sNaN Invalid, etc. */
- result=decCompare(lhs, rhs, 0); /* sign matters */
- if (result==BADINT) status|=DEC_Insufficient_storage; /* rare */
- else { /* valid compare */
- if (result==0) uprv_decNumberCopySign(res, lhs, rhs); /* easy */
- else { /* differ: need NextPlus or NextMinus */
- uByte sub; /* add or subtract */
- if (result<0) { /* lhs<rhs, do nextplus */
- /* -Infinity is the special case */
- if ((lhs->bits&(DECINF|DECNEG))==(DECINF|DECNEG)) {
- decSetMaxValue(res, set);
- res->bits=DECNEG; /* negative */
- return res; /* there is no status to set */
- }
- workset.round=DEC_ROUND_CEILING;
- sub=0; /* add, please */
- } /* plus */
- else { /* lhs>rhs, do nextminus */
- /* +Infinity is the special case */
- if ((lhs->bits&(DECINF|DECNEG))==DECINF) {
- decSetMaxValue(res, set);
- return res; /* there is no status to set */
- }
- workset.round=DEC_ROUND_FLOOR;
- sub=DECNEG; /* subtract, please */
- } /* minus */
- uprv_decNumberZero(&dtiny); /* start with 0 */
- dtiny.lsu[0]=1; /* make number that is .. */
- dtiny.exponent=DEC_MIN_EMIN-1; /* .. smaller than tiniest */
- decAddOp(res, lhs, &dtiny, &workset, sub, &status); /* + or - */
- /* turn off exceptions if the result is a normal number */
- /* (including Nmin), otherwise let all status through */
- if (uprv_decNumberIsNormal(res, set)) status=0;
- } /* unequal */
- } /* compare OK */
- } /* numeric */
- if (status!=0) decStatus(res, status, set);
- return res;
- } /* decNumberNextToward */
-
-/* ------------------------------------------------------------------ */
-/* decNumberOr -- OR two Numbers, digitwise */
-/* */
-/* This computes C = A | B */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=X|X) */
-/* lhs is A */
-/* rhs is B */
-/* set is the context (used for result length and error report) */
-/* */
-/* C must have space for set->digits digits. */
-/* */
-/* Logical function restrictions apply (see above); a NaN is */
-/* returned with Invalid_operation if a restriction is violated. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberOr(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- const Unit *ua, *ub; /* -> operands */
- const Unit *msua, *msub; /* -> operand msus */
- Unit *uc, *msuc; /* -> result and its msu */
- Int msudigs; /* digits in res msu */
- #if DECCHECK
- if (decCheckOperands(res, lhs, rhs, set)) return res;
- #endif
-
- if (lhs->exponent!=0 || decNumberIsSpecial(lhs) || decNumberIsNegative(lhs)
- || rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) {
- decStatus(res, DEC_Invalid_operation, set);
- return res;
- }
- /* operands are valid */
- ua=lhs->lsu; /* bottom-up */
- ub=rhs->lsu; /* .. */
- uc=res->lsu; /* .. */
- msua=ua+D2U(lhs->digits)-1; /* -> msu of lhs */
- msub=ub+D2U(rhs->digits)-1; /* -> msu of rhs */
- msuc=uc+D2U(set->digits)-1; /* -> msu of result */
- msudigs=MSUDIGITS(set->digits); /* [faster than remainder] */
- for (; uc<=msuc; ua++, ub++, uc++) { /* Unit loop */
- Unit a, b; /* extract units */
- if (ua>msua) a=0;
- else a=*ua;
- if (ub>msub) b=0;
- else b=*ub;
- *uc=0; /* can now write back */
- if (a|b) { /* maybe 1 bits to examine */
- Int i, j;
- /* This loop could be unrolled and/or use BIN2BCD tables */
- for (i=0; i<DECDPUN; i++) {
- if ((a|b)&1) *uc=*uc+(Unit)powers[i]; /* effect OR */
- j=a%10;
- a=a/10;
- j|=b%10;
- b=b/10;
- if (j>1) {
- decStatus(res, DEC_Invalid_operation, set);
- return res;
- }
- if (uc==msuc && i==msudigs-1) break; /* just did final digit */
- } /* each digit */
- } /* non-zero */
- } /* each unit */
- /* [here uc-1 is the msu of the result] */
- res->digits=decGetDigits(res->lsu, static_cast<int32_t>(uc-res->lsu));
- res->exponent=0; /* integer */
- res->bits=0; /* sign=0 */
- return res; /* [no status to set] */
- } /* decNumberOr */
-
-/* ------------------------------------------------------------------ */
-/* decNumberPlus -- prefix plus operator */
-/* */
-/* This computes C = 0 + A */
-/* */
-/* res is C, the result. C may be A */
-/* rhs is A */
-/* set is the context */
-/* */
-/* See also decNumberCopy for a quiet bitwise version of this. */
-/* C must have space for set->digits digits. */
-/* ------------------------------------------------------------------ */
-/* This simply uses AddOp; Add will take fast path after preparing A. */
-/* Performance is a concern here, as this routine is often used to */
-/* check operands and apply rounding and overflow/underflow testing. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberPlus(decNumber *res, const decNumber *rhs,
- decContext *set) {
- decNumber dzero;
- uInt status=0; /* accumulator */
- #if DECCHECK
- if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
- #endif
-
- uprv_decNumberZero(&dzero); /* make 0 */
- dzero.exponent=rhs->exponent; /* [no coefficient expansion] */
- decAddOp(res, &dzero, rhs, set, 0, &status);
- if (status!=0) decStatus(res, status, set);
- #if DECCHECK
- decCheckInexact(res, set);
- #endif
- return res;
- } /* decNumberPlus */
-
-/* ------------------------------------------------------------------ */
-/* decNumberMultiply -- multiply two Numbers */
-/* */
-/* This computes C = A x B */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=X+X) */
-/* lhs is A */
-/* rhs is B */
-/* set is the context */
-/* */
-/* C must have space for set->digits digits. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberMultiply(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- uInt status=0; /* accumulator */
- decMultiplyOp(res, lhs, rhs, set, &status);
- if (status!=0) decStatus(res, status, set);
- #if DECCHECK
- decCheckInexact(res, set);
- #endif
- return res;
- } /* decNumberMultiply */
-
-/* ------------------------------------------------------------------ */
-/* decNumberPower -- raise a number to a power */
-/* */
-/* This computes C = A ** B */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=X**X) */
-/* lhs is A */
-/* rhs is B */
-/* set is the context */
-/* */
-/* C must have space for set->digits digits. */
-/* */
-/* Mathematical function restrictions apply (see above); a NaN is */
-/* returned with Invalid_operation if a restriction is violated. */
-/* */
-/* However, if 1999999997<=B<=999999999 and B is an integer then the */
-/* restrictions on A and the context are relaxed to the usual bounds, */
-/* for compatibility with the earlier (integer power only) version */
-/* of this function. */
-/* */
-/* When B is an integer, the result may be exact, even if rounded. */
-/* */
-/* The final result is rounded according to the context; it will */
-/* almost always be correctly rounded, but may be up to 1 ulp in */
-/* error in rare cases. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberPower(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- #if DECSUBSET
- decNumber *alloclhs=NULL; /* non-NULL if rounded lhs allocated */
- decNumber *allocrhs=NULL; /* .., rhs */
- #endif
- decNumber *allocdac=NULL; /* -> allocated acc buffer, iff used */
- decNumber *allocinv=NULL; /* -> allocated 1/x buffer, iff used */
- Int reqdigits=set->digits; /* requested DIGITS */
- Int n; /* rhs in binary */
- Flag rhsint=0; /* 1 if rhs is an integer */
- Flag useint=0; /* 1 if can use integer calculation */
- Flag isoddint=0; /* 1 if rhs is an integer and odd */
- Int i; /* work */
- #if DECSUBSET
- Int dropped; /* .. */
- #endif
- uInt needbytes; /* buffer size needed */
- Flag seenbit; /* seen a bit while powering */
- Int residue=0; /* rounding residue */
- uInt status=0; /* accumulators */
- uByte bits=0; /* result sign if errors */
- decContext aset; /* working context */
- decNumber dnOne; /* work value 1... */
- /* local accumulator buffer [a decNumber, with digits+elength+1 digits] */
- decNumber dacbuff[D2N(DECBUFFER+9)];
- decNumber *dac=dacbuff; /* -> result accumulator */
- /* same again for possible 1/lhs calculation */
- decNumber invbuff[D2N(DECBUFFER+9)];
-
- #if DECCHECK
- if (decCheckOperands(res, lhs, rhs, set)) return res;
- #endif
-
- do { /* protect allocated storage */
- #if DECSUBSET
- if (!set->extended) { /* reduce operands and set status, as needed */
- if (lhs->digits>reqdigits) {
- alloclhs=decRoundOperand(lhs, set, &status);
- if (alloclhs==NULL) break;
- lhs=alloclhs;
- }
- if (rhs->digits>reqdigits) {
- allocrhs=decRoundOperand(rhs, set, &status);
- if (allocrhs==NULL) break;
- rhs=allocrhs;
- }
- }
- #endif
- /* [following code does not require input rounding] */
-
- /* handle NaNs and rhs Infinity (lhs infinity is harder) */
- if (SPECIALARGS) {
- if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs)) { /* NaNs */
- decNaNs(res, lhs, rhs, set, &status);
- break;}
- if (decNumberIsInfinite(rhs)) { /* rhs Infinity */
- Flag rhsneg=rhs->bits&DECNEG; /* save rhs sign */
- if (decNumberIsNegative(lhs) /* lhs<0 */
- && !decNumberIsZero(lhs)) /* .. */
- status|=DEC_Invalid_operation;
- else { /* lhs >=0 */
- uprv_decNumberZero(&dnOne); /* set up 1 */
- dnOne.lsu[0]=1;
- uprv_decNumberCompare(dac, lhs, &dnOne, set); /* lhs ? 1 */
- uprv_decNumberZero(res); /* prepare for 0/1/Infinity */
- if (decNumberIsNegative(dac)) { /* lhs<1 */
- if (rhsneg) res->bits|=DECINF; /* +Infinity [else is +0] */
- }
- else if (dac->lsu[0]==0) { /* lhs=1 */
- /* 1**Infinity is inexact, so return fully-padded 1.0000 */
- Int shift=set->digits-1;
- *res->lsu=1; /* was 0, make int 1 */
- res->digits=decShiftToMost(res->lsu, 1, shift);
- res->exponent=-shift; /* make 1.0000... */
- status|=DEC_Inexact|DEC_Rounded; /* deemed inexact */
- }
- else { /* lhs>1 */
- if (!rhsneg) res->bits|=DECINF; /* +Infinity [else is +0] */
- }
- } /* lhs>=0 */
- break;}
- /* [lhs infinity drops through] */
- } /* specials */
-
- /* Original rhs may be an integer that fits and is in range */
- n=decGetInt(rhs);
- if (n!=BADINT) { /* it is an integer */
- rhsint=1; /* record the fact for 1**n */
- isoddint=(Flag)n&1; /* [works even if big] */
- if (n!=BIGEVEN && n!=BIGODD) /* can use integer path? */
- useint=1; /* looks good */
- }
-
- if (decNumberIsNegative(lhs) /* -x .. */
- && isoddint) bits=DECNEG; /* .. to an odd power */
-
- /* handle LHS infinity */
- if (decNumberIsInfinite(lhs)) { /* [NaNs already handled] */
- uByte rbits=rhs->bits; /* save */
- uprv_decNumberZero(res); /* prepare */
- if (n==0) *res->lsu=1; /* [-]Inf**0 => 1 */
- else {
- /* -Inf**nonint -> error */
- if (!rhsint && decNumberIsNegative(lhs)) {
- status|=DEC_Invalid_operation; /* -Inf**nonint is error */
- break;}
- if (!(rbits & DECNEG)) bits|=DECINF; /* was not a **-n */
- /* [otherwise will be 0 or -0] */
- res->bits=bits;
- }
- break;}
-
- /* similarly handle LHS zero */
- if (decNumberIsZero(lhs)) {
- if (n==0) { /* 0**0 => Error */
- #if DECSUBSET
- if (!set->extended) { /* [unless subset] */
- uprv_decNumberZero(res);
- *res->lsu=1; /* return 1 */
- break;}
- #endif
- status|=DEC_Invalid_operation;
- }
- else { /* 0**x */
- uByte rbits=rhs->bits; /* save */
- if (rbits & DECNEG) { /* was a 0**(-n) */
- #if DECSUBSET
- if (!set->extended) { /* [bad if subset] */
- status|=DEC_Invalid_operation;
- break;}
- #endif
- bits|=DECINF;
- }
- uprv_decNumberZero(res); /* prepare */
- /* [otherwise will be 0 or -0] */
- res->bits=bits;
- }
- break;}
-
- /* here both lhs and rhs are finite; rhs==0 is handled in the */
- /* integer path. Next handle the non-integer cases */
- if (!useint) { /* non-integral rhs */
- /* any -ve lhs is bad, as is either operand or context out of */
- /* bounds */
- if (decNumberIsNegative(lhs)) {
- status|=DEC_Invalid_operation;
- break;}
- if (decCheckMath(lhs, set, &status)
- || decCheckMath(rhs, set, &status)) break; /* variable status */
-
- uprv_decContextDefault(&aset, DEC_INIT_DECIMAL64); /* clean context */
- aset.emax=DEC_MAX_MATH; /* usual bounds */
- aset.emin=-DEC_MAX_MATH; /* .. */
- aset.clamp=0; /* and no concrete format */
-
- /* calculate the result using exp(ln(lhs)*rhs), which can */
- /* all be done into the accumulator, dac. The precision needed */
- /* is enough to contain the full information in the lhs (which */
- /* is the total digits, including exponent), or the requested */
- /* precision, if larger, + 4; 6 is used for the exponent */
- /* maximum length, and this is also used when it is shorter */
- /* than the requested digits as it greatly reduces the >0.5 ulp */
- /* cases at little cost (because Ln doubles digits each */
- /* iteration so a few extra digits rarely causes an extra */
- /* iteration) */
- aset.digits=MAXI(lhs->digits, set->digits)+6+4;
- } /* non-integer rhs */
-
- else { /* rhs is in-range integer */
- if (n==0) { /* x**0 = 1 */
- /* (0**0 was handled above) */
- uprv_decNumberZero(res); /* result=1 */
- *res->lsu=1; /* .. */
- break;}
- /* rhs is a non-zero integer */
- if (n<0) n=-n; /* use abs(n) */
-
- aset=*set; /* clone the context */
- aset.round=DEC_ROUND_HALF_EVEN; /* internally use balanced */
- /* calculate the working DIGITS */
- aset.digits=reqdigits+(rhs->digits+rhs->exponent)+2;
- #if DECSUBSET
- if (!set->extended) aset.digits--; /* use classic precision */
- #endif
- /* it's an error if this is more than can be handled */
- if (aset.digits>DECNUMMAXP) {status|=DEC_Invalid_operation; break;}
- } /* integer path */
-
- /* aset.digits is the count of digits for the accumulator needed */
- /* if accumulator is too long for local storage, then allocate */
- needbytes=sizeof(decNumber)+(D2U(aset.digits)-1)*sizeof(Unit);
- /* [needbytes also used below if 1/lhs needed] */
- if (needbytes>sizeof(dacbuff)) {
- allocdac=(decNumber *)malloc(needbytes);
- if (allocdac==NULL) { /* hopeless -- abandon */
- status|=DEC_Insufficient_storage;
- break;}
- dac=allocdac; /* use the allocated space */
- }
- /* here, aset is set up and accumulator is ready for use */
-
- if (!useint) { /* non-integral rhs */
- /* x ** y; special-case x=1 here as it will otherwise always */
- /* reduce to integer 1; decLnOp has a fastpath which detects */
- /* the case of x=1 */
- decLnOp(dac, lhs, &aset, &status); /* dac=ln(lhs) */
- /* [no error possible, as lhs 0 already handled] */
- if (ISZERO(dac)) { /* x==1, 1.0, etc. */
- /* need to return fully-padded 1.0000 etc., but rhsint->1 */
- *dac->lsu=1; /* was 0, make int 1 */
- if (!rhsint) { /* add padding */
- Int shift=set->digits-1;
- dac->digits=decShiftToMost(dac->lsu, 1, shift);
- dac->exponent=-shift; /* make 1.0000... */
- status|=DEC_Inexact|DEC_Rounded; /* deemed inexact */
- }
- }
- else {
- decMultiplyOp(dac, dac, rhs, &aset, &status); /* dac=dac*rhs */
- decExpOp(dac, dac, &aset, &status); /* dac=exp(dac) */
- }
- /* and drop through for final rounding */
- } /* non-integer rhs */
-
- else { /* carry on with integer */
- uprv_decNumberZero(dac); /* acc=1 */
- *dac->lsu=1; /* .. */
-
- /* if a negative power the constant 1 is needed, and if not subset */
- /* invert the lhs now rather than inverting the result later */
- if (decNumberIsNegative(rhs)) { /* was a **-n [hence digits>0] */
- decNumber *inv=invbuff; /* asssume use fixed buffer */
- uprv_decNumberCopy(&dnOne, dac); /* dnOne=1; [needed now or later] */
- #if DECSUBSET
- if (set->extended) { /* need to calculate 1/lhs */
- #endif
- /* divide lhs into 1, putting result in dac [dac=1/dac] */
- decDivideOp(dac, &dnOne, lhs, &aset, DIVIDE, &status);
- /* now locate or allocate space for the inverted lhs */
- if (needbytes>sizeof(invbuff)) {
- allocinv=(decNumber *)malloc(needbytes);
- if (allocinv==NULL) { /* hopeless -- abandon */
- status|=DEC_Insufficient_storage;
- break;}
- inv=allocinv; /* use the allocated space */
- }
- /* [inv now points to big-enough buffer or allocated storage] */
- uprv_decNumberCopy(inv, dac); /* copy the 1/lhs */
- uprv_decNumberCopy(dac, &dnOne); /* restore acc=1 */
- lhs=inv; /* .. and go forward with new lhs */
- #if DECSUBSET
- }
- #endif
- }
-
- /* Raise-to-the-power loop... */
- seenbit=0; /* set once a 1-bit is encountered */
- for (i=1;;i++){ /* for each bit [top bit ignored] */
- /* abandon if had overflow or terminal underflow */
- if (status & (DEC_Overflow|DEC_Underflow)) { /* interesting? */
- if (status&DEC_Overflow || ISZERO(dac)) break;
- }
- /* [the following two lines revealed an optimizer bug in a C++ */
- /* compiler, with symptom: 5**3 -> 25, when n=n+n was used] */
- n=n<<1; /* move next bit to testable position */
- if (n<0) { /* top bit is set */
- seenbit=1; /* OK, significant bit seen */
- decMultiplyOp(dac, dac, lhs, &aset, &status); /* dac=dac*x */
- }
- if (i==31) break; /* that was the last bit */
- if (!seenbit) continue; /* no need to square 1 */
- decMultiplyOp(dac, dac, dac, &aset, &status); /* dac=dac*dac [square] */
- } /*i*/ /* 32 bits */
-
- /* complete internal overflow or underflow processing */
- if (status & (DEC_Overflow|DEC_Underflow)) {
- #if DECSUBSET
- /* If subset, and power was negative, reverse the kind of -erflow */
- /* [1/x not yet done] */
- if (!set->extended && decNumberIsNegative(rhs)) {
- if (status & DEC_Overflow)
- status^=DEC_Overflow | DEC_Underflow | DEC_Subnormal;
- else { /* trickier -- Underflow may or may not be set */
- status&=~(DEC_Underflow | DEC_Subnormal); /* [one or both] */
- status|=DEC_Overflow;
- }
- }
- #endif
- dac->bits=(dac->bits & ~DECNEG) | bits; /* force correct sign */
- /* round subnormals [to set.digits rather than aset.digits] */
- /* or set overflow result similarly as required */
- decFinalize(dac, set, &residue, &status);
- uprv_decNumberCopy(res, dac); /* copy to result (is now OK length) */
- break;
- }
-
- #if DECSUBSET
- if (!set->extended && /* subset math */
- decNumberIsNegative(rhs)) { /* was a **-n [hence digits>0] */
- /* so divide result into 1 [dac=1/dac] */
- decDivideOp(dac, &dnOne, dac, &aset, DIVIDE, &status);
- }
- #endif
- } /* rhs integer path */
-
- /* reduce result to the requested length and copy to result */
- decCopyFit(res, dac, set, &residue, &status);
- decFinish(res, set, &residue, &status); /* final cleanup */
- #if DECSUBSET
- if (!set->extended) decTrim(res, set, 0, 1, &dropped); /* trailing zeros */
- #endif
- } while(0); /* end protected */
-
- if (allocdac!=NULL) free(allocdac); /* drop any storage used */
- if (allocinv!=NULL) free(allocinv); /* .. */
- #if DECSUBSET
- if (alloclhs!=NULL) free(alloclhs); /* .. */
- if (allocrhs!=NULL) free(allocrhs); /* .. */
- #endif
- if (status!=0) decStatus(res, status, set);
- #if DECCHECK
- decCheckInexact(res, set);
- #endif
- return res;
- } /* decNumberPower */
-
-/* ------------------------------------------------------------------ */
-/* decNumberQuantize -- force exponent to requested value */
-/* */
-/* This computes C = op(A, B), where op adjusts the coefficient */
-/* of C (by rounding or shifting) such that the exponent (-scale) */
-/* of C has exponent of B. The numerical value of C will equal A, */
-/* except for the effects of any rounding that occurred. */
-/* */
-/* res is C, the result. C may be A or B */
-/* lhs is A, the number to adjust */
-/* rhs is B, the number with exponent to match */
-/* set is the context */
-/* */
-/* C must have space for set->digits digits. */
-/* */
-/* Unless there is an error or the result is infinite, the exponent */
-/* after the operation is guaranteed to be equal to that of B. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberQuantize(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- uInt status=0; /* accumulator */
- decQuantizeOp(res, lhs, rhs, set, 1, &status);
- if (status!=0) decStatus(res, status, set);
- return res;
- } /* decNumberQuantize */
-
-/* ------------------------------------------------------------------ */
-/* decNumberReduce -- remove trailing zeros */
-/* */
-/* This computes C = 0 + A, and normalizes the result */
-/* */
-/* res is C, the result. C may be A */
-/* rhs is A */
-/* set is the context */
-/* */
-/* C must have space for set->digits digits. */
-/* ------------------------------------------------------------------ */
-/* Previously known as Normalize */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberNormalize(decNumber *res, const decNumber *rhs,
- decContext *set) {
- return uprv_decNumberReduce(res, rhs, set);
- } /* decNumberNormalize */
-
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberReduce(decNumber *res, const decNumber *rhs,
- decContext *set) {
- #if DECSUBSET
- decNumber *allocrhs=NULL; /* non-NULL if rounded rhs allocated */
- #endif
- uInt status=0; /* as usual */
- Int residue=0; /* as usual */
- Int dropped; /* work */
-
- #if DECCHECK
- if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
- #endif
-
- do { /* protect allocated storage */
- #if DECSUBSET
- if (!set->extended) {
- /* reduce operand and set lostDigits status, as needed */
- if (rhs->digits>set->digits) {
- allocrhs=decRoundOperand(rhs, set, &status);
- if (allocrhs==NULL) break;
- rhs=allocrhs;
- }
- }
- #endif
- /* [following code does not require input rounding] */
-
- /* Infinities copy through; NaNs need usual treatment */
- if (decNumberIsNaN(rhs)) {
- decNaNs(res, rhs, NULL, set, &status);
- break;
- }
-
- /* reduce result to the requested length and copy to result */
- decCopyFit(res, rhs, set, &residue, &status); /* copy & round */
- decFinish(res, set, &residue, &status); /* cleanup/set flags */
- decTrim(res, set, 1, 0, &dropped); /* normalize in place */
- /* [may clamp] */
- } while(0); /* end protected */
-
- #if DECSUBSET
- if (allocrhs !=NULL) free(allocrhs); /* .. */
- #endif
- if (status!=0) decStatus(res, status, set);/* then report status */
- return res;
- } /* decNumberReduce */
-
-/* ------------------------------------------------------------------ */
-/* decNumberRescale -- force exponent to requested value */
-/* */
-/* This computes C = op(A, B), where op adjusts the coefficient */
-/* of C (by rounding or shifting) such that the exponent (-scale) */
-/* of C has the value B. The numerical value of C will equal A, */
-/* except for the effects of any rounding that occurred. */
-/* */
-/* res is C, the result. C may be A or B */
-/* lhs is A, the number to adjust */
-/* rhs is B, the requested exponent */
-/* set is the context */
-/* */
-/* C must have space for set->digits digits. */
-/* */
-/* Unless there is an error or the result is infinite, the exponent */
-/* after the operation is guaranteed to be equal to B. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberRescale(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- uInt status=0; /* accumulator */
- decQuantizeOp(res, lhs, rhs, set, 0, &status);
- if (status!=0) decStatus(res, status, set);
- return res;
- } /* decNumberRescale */
-
-/* ------------------------------------------------------------------ */
-/* decNumberRemainder -- divide and return remainder */
-/* */
-/* This computes C = A % B */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=X%X) */
-/* lhs is A */
-/* rhs is B */
-/* set is the context */
-/* */
-/* C must have space for set->digits digits. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberRemainder(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- uInt status=0; /* accumulator */
- decDivideOp(res, lhs, rhs, set, REMAINDER, &status);
- if (status!=0) decStatus(res, status, set);
- #if DECCHECK
- decCheckInexact(res, set);
- #endif
- return res;
- } /* decNumberRemainder */
-
-/* ------------------------------------------------------------------ */
-/* decNumberRemainderNear -- divide and return remainder from nearest */
-/* */
-/* This computes C = A % B, where % is the IEEE remainder operator */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=X%X) */
-/* lhs is A */
-/* rhs is B */
-/* set is the context */
-/* */
-/* C must have space for set->digits digits. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberRemainderNear(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- uInt status=0; /* accumulator */
- decDivideOp(res, lhs, rhs, set, REMNEAR, &status);
- if (status!=0) decStatus(res, status, set);
- #if DECCHECK
- decCheckInexact(res, set);
- #endif
- return res;
- } /* decNumberRemainderNear */
-
-/* ------------------------------------------------------------------ */
-/* decNumberRotate -- rotate the coefficient of a Number left/right */
-/* */
-/* This computes C = A rot B (in base ten and rotating set->digits */
-/* digits). */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=XrotX) */
-/* lhs is A */
-/* rhs is B, the number of digits to rotate (-ve to right) */
-/* set is the context */
-/* */
-/* The digits of the coefficient of A are rotated to the left (if B */
-/* is positive) or to the right (if B is negative) without adjusting */
-/* the exponent or the sign of A. If lhs->digits is less than */
-/* set->digits the coefficient is padded with zeros on the left */
-/* before the rotate. Any leading zeros in the result are removed */
-/* as usual. */
-/* */
-/* B must be an integer (q=0) and in the range -set->digits through */
-/* +set->digits. */
-/* C must have space for set->digits digits. */
-/* NaNs are propagated as usual. Infinities are unaffected (but */
-/* B must be valid). No status is set unless B is invalid or an */
-/* operand is an sNaN. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberRotate(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- uInt status=0; /* accumulator */
- Int rotate; /* rhs as an Int */
-
- #if DECCHECK
- if (decCheckOperands(res, lhs, rhs, set)) return res;
- #endif
-
- /* NaNs propagate as normal */
- if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs))
- decNaNs(res, lhs, rhs, set, &status);
- /* rhs must be an integer */
- else if (decNumberIsInfinite(rhs) || rhs->exponent!=0)
- status=DEC_Invalid_operation;
- else { /* both numeric, rhs is an integer */
- rotate=decGetInt(rhs); /* [cannot fail] */
- if (rotate==BADINT /* something bad .. */
- || rotate==BIGODD || rotate==BIGEVEN /* .. very big .. */
- || abs(rotate)>set->digits) /* .. or out of range */
- status=DEC_Invalid_operation;
- else { /* rhs is OK */
- uprv_decNumberCopy(res, lhs);
- /* convert -ve rotate to equivalent positive rotation */
- if (rotate<0) rotate=set->digits+rotate;
- if (rotate!=0 && rotate!=set->digits /* zero or full rotation */
- && !decNumberIsInfinite(res)) { /* lhs was infinite */
- /* left-rotate to do; 0 < rotate < set->digits */
- uInt units, shift; /* work */
- uInt msudigits; /* digits in result msu */
- Unit *msu=res->lsu+D2U(res->digits)-1; /* current msu */
- Unit *msumax=res->lsu+D2U(set->digits)-1; /* rotation msu */
- for (msu++; msu<=msumax; msu++) *msu=0; /* ensure high units=0 */
- res->digits=set->digits; /* now full-length */
- msudigits=MSUDIGITS(res->digits); /* actual digits in msu */
-
- /* rotation here is done in-place, in three steps */
- /* 1. shift all to least up to one unit to unit-align final */
- /* lsd [any digits shifted out are rotated to the left, */
- /* abutted to the original msd (which may require split)] */
- /* */
- /* [if there are no whole units left to rotate, the */
- /* rotation is now complete] */
- /* */
- /* 2. shift to least, from below the split point only, so that */
- /* the final msd is in the right place in its Unit [any */
- /* digits shifted out will fit exactly in the current msu, */
- /* left aligned, no split required] */
- /* */
- /* 3. rotate all the units by reversing left part, right */
- /* part, and then whole */
- /* */
- /* example: rotate right 8 digits (2 units + 2), DECDPUN=3. */
- /* */
- /* start: 00a bcd efg hij klm npq */
- /* */
- /* 1a 000 0ab cde fgh|ijk lmn [pq saved] */
- /* 1b 00p qab cde fgh|ijk lmn */
- /* */
- /* 2a 00p qab cde fgh|00i jkl [mn saved] */
- /* 2b mnp qab cde fgh|00i jkl */
- /* */
- /* 3a fgh cde qab mnp|00i jkl */
- /* 3b fgh cde qab mnp|jkl 00i */
- /* 3c 00i jkl mnp qab cde fgh */
-
- /* Step 1: amount to shift is the partial right-rotate count */
- rotate=set->digits-rotate; /* make it right-rotate */
- units=rotate/DECDPUN; /* whole units to rotate */
- shift=rotate%DECDPUN; /* left-over digits count */
- if (shift>0) { /* not an exact number of units */
- uInt save=res->lsu[0]%powers[shift]; /* save low digit(s) */
- decShiftToLeast(res->lsu, D2U(res->digits), shift);
- if (shift>msudigits) { /* msumax-1 needs >0 digits */
- uInt rem=save%powers[shift-msudigits];/* split save */
- *msumax=(Unit)(save/powers[shift-msudigits]); /* and insert */
- *(msumax-1)=*(msumax-1)
- +(Unit)(rem*powers[DECDPUN-(shift-msudigits)]); /* .. */
- }
- else { /* all fits in msumax */
- *msumax=*msumax+(Unit)(save*powers[msudigits-shift]); /* [maybe *1] */
- }
- } /* digits shift needed */
-
- /* If whole units to rotate... */
- if (units>0) { /* some to do */
- /* Step 2: the units to touch are the whole ones in rotate, */
- /* if any, and the shift is DECDPUN-msudigits (which may be */
- /* 0, again) */
- shift=DECDPUN-msudigits;
- if (shift>0) { /* not an exact number of units */
- uInt save=res->lsu[0]%powers[shift]; /* save low digit(s) */
- decShiftToLeast(res->lsu, units, shift);
- *msumax=*msumax+(Unit)(save*powers[msudigits]);
- } /* partial shift needed */
-
- /* Step 3: rotate the units array using triple reverse */
- /* (reversing is easy and fast) */
- decReverse(res->lsu+units, msumax); /* left part */
- decReverse(res->lsu, res->lsu+units-1); /* right part */
- decReverse(res->lsu, msumax); /* whole */
- } /* whole units to rotate */
- /* the rotation may have left an undetermined number of zeros */
- /* on the left, so true length needs to be calculated */
- res->digits=decGetDigits(res->lsu, static_cast<int32_t>(msumax-res->lsu+1));
- } /* rotate needed */
- } /* rhs OK */
- } /* numerics */
- if (status!=0) decStatus(res, status, set);
- return res;
- } /* decNumberRotate */
-
-/* ------------------------------------------------------------------ */
-/* decNumberSameQuantum -- test for equal exponents */
-/* */
-/* res is the result number, which will contain either 0 or 1 */
-/* lhs is a number to test */
-/* rhs is the second (usually a pattern) */
-/* */
-/* No errors are possible and no context is needed. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberSameQuantum(decNumber *res, const decNumber *lhs,
- const decNumber *rhs) {
- Unit ret=0; /* return value */
-
- #if DECCHECK
- if (decCheckOperands(res, lhs, rhs, DECUNCONT)) return res;
- #endif
-
- if (SPECIALARGS) {
- if (decNumberIsNaN(lhs) && decNumberIsNaN(rhs)) ret=1;
- else if (decNumberIsInfinite(lhs) && decNumberIsInfinite(rhs)) ret=1;
- /* [anything else with a special gives 0] */
- }
- else if (lhs->exponent==rhs->exponent) ret=1;
-
- uprv_decNumberZero(res); /* OK to overwrite an operand now */
- *res->lsu=ret;
- return res;
- } /* decNumberSameQuantum */
-
-/* ------------------------------------------------------------------ */
-/* decNumberScaleB -- multiply by a power of 10 */
-/* */
-/* This computes C = A x 10**B where B is an integer (q=0) with */
-/* maximum magnitude 2*(emax+digits) */
-/* */
-/* res is C, the result. C may be A or B */
-/* lhs is A, the number to adjust */
-/* rhs is B, the requested power of ten to use */
-/* set is the context */
-/* */
-/* C must have space for set->digits digits. */
-/* */
-/* The result may underflow or overflow. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberScaleB(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- Int reqexp; /* requested exponent change [B] */
- uInt status=0; /* accumulator */
- Int residue; /* work */
-
- #if DECCHECK
- if (decCheckOperands(res, lhs, rhs, set)) return res;
- #endif
-
- /* Handle special values except lhs infinite */
- if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs))
- decNaNs(res, lhs, rhs, set, &status);
- /* rhs must be an integer */
- else if (decNumberIsInfinite(rhs) || rhs->exponent!=0)
- status=DEC_Invalid_operation;
- else {
- /* lhs is a number; rhs is a finite with q==0 */
- reqexp=decGetInt(rhs); /* [cannot fail] */
- if (reqexp==BADINT /* something bad .. */
- || reqexp==BIGODD || reqexp==BIGEVEN /* .. very big .. */
- || abs(reqexp)>(2*(set->digits+set->emax))) /* .. or out of range */
- status=DEC_Invalid_operation;
- else { /* rhs is OK */
- uprv_decNumberCopy(res, lhs); /* all done if infinite lhs */
- if (!decNumberIsInfinite(res)) { /* prepare to scale */
- res->exponent+=reqexp; /* adjust the exponent */
- residue=0;
- decFinalize(res, set, &residue, &status); /* .. and check */
- } /* finite LHS */
- } /* rhs OK */
- } /* rhs finite */
- if (status!=0) decStatus(res, status, set);
- return res;
- } /* decNumberScaleB */
-
-/* ------------------------------------------------------------------ */
-/* decNumberShift -- shift the coefficient of a Number left or right */
-/* */
-/* This computes C = A << B or C = A >> -B (in base ten). */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=X<<X) */
-/* lhs is A */
-/* rhs is B, the number of digits to shift (-ve to right) */
-/* set is the context */
-/* */
-/* The digits of the coefficient of A are shifted to the left (if B */
-/* is positive) or to the right (if B is negative) without adjusting */
-/* the exponent or the sign of A. */
-/* */
-/* B must be an integer (q=0) and in the range -set->digits through */
-/* +set->digits. */
-/* C must have space for set->digits digits. */
-/* NaNs are propagated as usual. Infinities are unaffected (but */
-/* B must be valid). No status is set unless B is invalid or an */
-/* operand is an sNaN. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberShift(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- uInt status=0; /* accumulator */
- Int shift; /* rhs as an Int */
-
- #if DECCHECK
- if (decCheckOperands(res, lhs, rhs, set)) return res;
- #endif
-
- /* NaNs propagate as normal */
- if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs))
- decNaNs(res, lhs, rhs, set, &status);
- /* rhs must be an integer */
- else if (decNumberIsInfinite(rhs) || rhs->exponent!=0)
- status=DEC_Invalid_operation;
- else { /* both numeric, rhs is an integer */
- shift=decGetInt(rhs); /* [cannot fail] */
- if (shift==BADINT /* something bad .. */
- || shift==BIGODD || shift==BIGEVEN /* .. very big .. */
- || abs(shift)>set->digits) /* .. or out of range */
- status=DEC_Invalid_operation;
- else { /* rhs is OK */
- uprv_decNumberCopy(res, lhs);
- if (shift!=0 && !decNumberIsInfinite(res)) { /* something to do */
- if (shift>0) { /* to left */
- if (shift==set->digits) { /* removing all */
- *res->lsu=0; /* so place 0 */
- res->digits=1; /* .. */
- }
- else { /* */
- /* first remove leading digits if necessary */
- if (res->digits+shift>set->digits) {
- decDecap(res, res->digits+shift-set->digits);
- /* that updated res->digits; may have gone to 1 (for a */
- /* single digit or for zero */
- }
- if (res->digits>1 || *res->lsu) /* if non-zero.. */
- res->digits=decShiftToMost(res->lsu, res->digits, shift);
- } /* partial left */
- } /* left */
- else { /* to right */
- if (-shift>=res->digits) { /* discarding all */
- *res->lsu=0; /* so place 0 */
- res->digits=1; /* .. */
- }
- else {
- decShiftToLeast(res->lsu, D2U(res->digits), -shift);
- res->digits-=(-shift);
- }
- } /* to right */
- } /* non-0 non-Inf shift */
- } /* rhs OK */
- } /* numerics */
- if (status!=0) decStatus(res, status, set);
- return res;
- } /* decNumberShift */
-
-/* ------------------------------------------------------------------ */
-/* decNumberSquareRoot -- square root operator */
-/* */
-/* This computes C = squareroot(A) */
-/* */
-/* res is C, the result. C may be A */
-/* rhs is A */
-/* set is the context; note that rounding mode has no effect */
-/* */
-/* C must have space for set->digits digits. */
-/* ------------------------------------------------------------------ */
-/* This uses the following varying-precision algorithm in: */
-/* */
-/* Properly Rounded Variable Precision Square Root, T. E. Hull and */
-/* A. Abrham, ACM Transactions on Mathematical Software, Vol 11 #3, */
-/* pp229-237, ACM, September 1985. */
-/* */
-/* The square-root is calculated using Newton's method, after which */
-/* a check is made to ensure the result is correctly rounded. */
-/* */
-/* % [Reformatted original Numerical Turing source code follows.] */
-/* function sqrt(x : real) : real */
-/* % sqrt(x) returns the properly rounded approximation to the square */
-/* % root of x, in the precision of the calling environment, or it */
-/* % fails if x < 0. */
-/* % t e hull and a abrham, august, 1984 */
-/* if x <= 0 then */
-/* if x < 0 then */
-/* assert false */
-/* else */
-/* result 0 */
-/* end if */
-/* end if */
-/* var f := setexp(x, 0) % fraction part of x [0.1 <= x < 1] */
-/* var e := getexp(x) % exponent part of x */
-/* var approx : real */
-/* if e mod 2 = 0 then */
-/* approx := .259 + .819 * f % approx to root of f */
-/* else */
-/* f := f/l0 % adjustments */
-/* e := e + 1 % for odd */
-/* approx := .0819 + 2.59 * f % exponent */
-/* end if */
-/* */
-/* var p:= 3 */
-/* const maxp := currentprecision + 2 */
-/* loop */
-/* p := min(2*p - 2, maxp) % p = 4,6,10, . . . , maxp */
-/* precision p */
-/* approx := .5 * (approx + f/approx) */
-/* exit when p = maxp */
-/* end loop */
-/* */
-/* % approx is now within 1 ulp of the properly rounded square root */
-/* % of f; to ensure proper rounding, compare squares of (approx - */
-/* % l/2 ulp) and (approx + l/2 ulp) with f. */
-/* p := currentprecision */
-/* begin */
-/* precision p + 2 */
-/* const approxsubhalf := approx - setexp(.5, -p) */
-/* if mulru(approxsubhalf, approxsubhalf) > f then */
-/* approx := approx - setexp(.l, -p + 1) */
-/* else */
-/* const approxaddhalf := approx + setexp(.5, -p) */
-/* if mulrd(approxaddhalf, approxaddhalf) < f then */
-/* approx := approx + setexp(.l, -p + 1) */
-/* end if */
-/* end if */
-/* end */
-/* result setexp(approx, e div 2) % fix exponent */
-/* end sqrt */
-/* ------------------------------------------------------------------ */
-#if defined(__clang__) || U_GCC_MAJOR_MINOR >= 406
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Warray-bounds"
-#endif
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberSquareRoot(decNumber *res, const decNumber *rhs,
- decContext *set) {
- decContext workset, approxset; /* work contexts */
- decNumber dzero; /* used for constant zero */
- Int maxp; /* largest working precision */
- Int workp; /* working precision */
- Int residue=0; /* rounding residue */
- uInt status=0, ignore=0; /* status accumulators */
- uInt rstatus; /* .. */
- Int exp; /* working exponent */
- Int ideal; /* ideal (preferred) exponent */
- Int needbytes; /* work */
- Int dropped; /* .. */
-
- #if DECSUBSET
- decNumber *allocrhs=NULL; /* non-NULL if rounded rhs allocated */
- #endif
- /* buffer for f [needs +1 in case DECBUFFER 0] */
- decNumber buff[D2N(DECBUFFER+1)];
- /* buffer for a [needs +2 to match likely maxp] */
- decNumber bufa[D2N(DECBUFFER+2)];
- /* buffer for temporary, b [must be same size as a] */
- decNumber bufb[D2N(DECBUFFER+2)];
- decNumber *allocbuff=NULL; /* -> allocated buff, iff allocated */
- decNumber *allocbufa=NULL; /* -> allocated bufa, iff allocated */
- decNumber *allocbufb=NULL; /* -> allocated bufb, iff allocated */
- decNumber *f=buff; /* reduced fraction */
- decNumber *a=bufa; /* approximation to result */
- decNumber *b=bufb; /* intermediate result */
- /* buffer for temporary variable, up to 3 digits */
- decNumber buft[D2N(3)];
- decNumber *t=buft; /* up-to-3-digit constant or work */
-
- #if DECCHECK
- if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
- #endif
-
- do { /* protect allocated storage */
- #if DECSUBSET
- if (!set->extended) {
- /* reduce operand and set lostDigits status, as needed */
- if (rhs->digits>set->digits) {
- allocrhs=decRoundOperand(rhs, set, &status);
- if (allocrhs==NULL) break;
- /* [Note: 'f' allocation below could reuse this buffer if */
- /* used, but as this is rare they are kept separate for clarity.] */
- rhs=allocrhs;
- }
- }
- #endif
- /* [following code does not require input rounding] */
-
- /* handle infinities and NaNs */
- if (SPECIALARG) {
- if (decNumberIsInfinite(rhs)) { /* an infinity */
- if (decNumberIsNegative(rhs)) status|=DEC_Invalid_operation;
- else uprv_decNumberCopy(res, rhs); /* +Infinity */
- }
- else decNaNs(res, rhs, NULL, set, &status); /* a NaN */
- break;
- }
-
- /* calculate the ideal (preferred) exponent [floor(exp/2)] */
- /* [It would be nicer to write: ideal=rhs->exponent>>1, but this */
- /* generates a compiler warning. Generated code is the same.] */
- ideal=(rhs->exponent&~1)/2; /* target */
-
- /* handle zeros */
- if (ISZERO(rhs)) {
- uprv_decNumberCopy(res, rhs); /* could be 0 or -0 */
- res->exponent=ideal; /* use the ideal [safe] */
- /* use decFinish to clamp any out-of-range exponent, etc. */
- decFinish(res, set, &residue, &status);
- break;
- }
-
- /* any other -x is an oops */
- if (decNumberIsNegative(rhs)) {
- status|=DEC_Invalid_operation;
- break;
- }
-
- /* space is needed for three working variables */
- /* f -- the same precision as the RHS, reduced to 0.01->0.99... */
- /* a -- Hull's approximation -- precision, when assigned, is */
- /* currentprecision+1 or the input argument precision, */
- /* whichever is larger (+2 for use as temporary) */
- /* b -- intermediate temporary result (same size as a) */
- /* if any is too long for local storage, then allocate */
- workp=MAXI(set->digits+1, rhs->digits); /* actual rounding precision */
- workp=MAXI(workp, 7); /* at least 7 for low cases */
- maxp=workp+2; /* largest working precision */
-
- needbytes=sizeof(decNumber)+(D2U(rhs->digits)-1)*sizeof(Unit);
- if (needbytes>(Int)sizeof(buff)) {
- allocbuff=(decNumber *)malloc(needbytes);
- if (allocbuff==NULL) { /* hopeless -- abandon */
- status|=DEC_Insufficient_storage;
- break;}
- f=allocbuff; /* use the allocated space */
- }
- /* a and b both need to be able to hold a maxp-length number */
- needbytes=sizeof(decNumber)+(D2U(maxp)-1)*sizeof(Unit);
- if (needbytes>(Int)sizeof(bufa)) { /* [same applies to b] */
- allocbufa=(decNumber *)malloc(needbytes);
- allocbufb=(decNumber *)malloc(needbytes);
- if (allocbufa==NULL || allocbufb==NULL) { /* hopeless */
- status|=DEC_Insufficient_storage;
- break;}
- a=allocbufa; /* use the allocated spaces */
- b=allocbufb; /* .. */
- }
-
- /* copy rhs -> f, save exponent, and reduce so 0.1 <= f < 1 */
- uprv_decNumberCopy(f, rhs);
- exp=f->exponent+f->digits; /* adjusted to Hull rules */
- f->exponent=-(f->digits); /* to range */
-
- /* set up working context */
- uprv_decContextDefault(&workset, DEC_INIT_DECIMAL64);
- workset.emax=DEC_MAX_EMAX;
- workset.emin=DEC_MIN_EMIN;
-
- /* [Until further notice, no error is possible and status bits */
- /* (Rounded, etc.) should be ignored, not accumulated.] */
-
- /* Calculate initial approximation, and allow for odd exponent */
- workset.digits=workp; /* p for initial calculation */
- t->bits=0; t->digits=3;
- a->bits=0; a->digits=3;
- if ((exp & 1)==0) { /* even exponent */
- /* Set t=0.259, a=0.819 */
- t->exponent=-3;
- a->exponent=-3;
- #if DECDPUN>=3
- t->lsu[0]=259;
- a->lsu[0]=819;
- #elif DECDPUN==2
- t->lsu[0]=59; t->lsu[1]=2;
- a->lsu[0]=19; a->lsu[1]=8;
- #else
- t->lsu[0]=9; t->lsu[1]=5; t->lsu[2]=2;
- a->lsu[0]=9; a->lsu[1]=1; a->lsu[2]=8;
- #endif
- }
- else { /* odd exponent */
- /* Set t=0.0819, a=2.59 */
- f->exponent--; /* f=f/10 */
- exp++; /* e=e+1 */
- t->exponent=-4;
- a->exponent=-2;
- #if DECDPUN>=3
- t->lsu[0]=819;
- a->lsu[0]=259;
- #elif DECDPUN==2
- t->lsu[0]=19; t->lsu[1]=8;
- a->lsu[0]=59; a->lsu[1]=2;
- #else
- t->lsu[0]=9; t->lsu[1]=1; t->lsu[2]=8;
- a->lsu[0]=9; a->lsu[1]=5; a->lsu[2]=2;
- #endif
- }
-
- decMultiplyOp(a, a, f, &workset, &ignore); /* a=a*f */
- decAddOp(a, a, t, &workset, 0, &ignore); /* ..+t */
- /* [a is now the initial approximation for sqrt(f), calculated with */
- /* currentprecision, which is also a's precision.] */
-
- /* the main calculation loop */
- uprv_decNumberZero(&dzero); /* make 0 */
- uprv_decNumberZero(t); /* set t = 0.5 */
- t->lsu[0]=5; /* .. */
- t->exponent=-1; /* .. */
- workset.digits=3; /* initial p */
- for (; workset.digits<maxp;) {
- /* set p to min(2*p - 2, maxp) [hence 3; or: 4, 6, 10, ... , maxp] */
- workset.digits=MINI(workset.digits*2-2, maxp);
- /* a = 0.5 * (a + f/a) */
- /* [calculated at p then rounded to currentprecision] */
- decDivideOp(b, f, a, &workset, DIVIDE, &ignore); /* b=f/a */
- decAddOp(b, b, a, &workset, 0, &ignore); /* b=b+a */
- decMultiplyOp(a, b, t, &workset, &ignore); /* a=b*0.5 */
- } /* loop */
-
- /* Here, 0.1 <= a < 1 [Hull], and a has maxp digits */
- /* now reduce to length, etc.; this needs to be done with a */
- /* having the correct exponent so as to handle subnormals */
- /* correctly */
- approxset=*set; /* get emin, emax, etc. */
- approxset.round=DEC_ROUND_HALF_EVEN;
- a->exponent+=exp/2; /* set correct exponent */
- rstatus=0; /* clear status */
- residue=0; /* .. and accumulator */
- decCopyFit(a, a, &approxset, &residue, &rstatus); /* reduce (if needed) */
- decFinish(a, &approxset, &residue, &rstatus); /* clean and finalize */
-
- /* Overflow was possible if the input exponent was out-of-range, */
- /* in which case quit */
- if (rstatus&DEC_Overflow) {
- status=rstatus; /* use the status as-is */
- uprv_decNumberCopy(res, a); /* copy to result */
- break;
- }
-
- /* Preserve status except Inexact/Rounded */
- status|=(rstatus & ~(DEC_Rounded|DEC_Inexact));
-
- /* Carry out the Hull correction */
- a->exponent-=exp/2; /* back to 0.1->1 */
-
- /* a is now at final precision and within 1 ulp of the properly */
- /* rounded square root of f; to ensure proper rounding, compare */
- /* squares of (a - l/2 ulp) and (a + l/2 ulp) with f. */
- /* Here workset.digits=maxp and t=0.5, and a->digits determines */
- /* the ulp */
- workset.digits--; /* maxp-1 is OK now */
- t->exponent=-a->digits-1; /* make 0.5 ulp */
- decAddOp(b, a, t, &workset, DECNEG, &ignore); /* b = a - 0.5 ulp */
- workset.round=DEC_ROUND_UP;
- decMultiplyOp(b, b, b, &workset, &ignore); /* b = mulru(b, b) */
- decCompareOp(b, f, b, &workset, COMPARE, &ignore); /* b ? f, reversed */
- if (decNumberIsNegative(b)) { /* f < b [i.e., b > f] */
- /* this is the more common adjustment, though both are rare */
- t->exponent++; /* make 1.0 ulp */
- t->lsu[0]=1; /* .. */
- decAddOp(a, a, t, &workset, DECNEG, &ignore); /* a = a - 1 ulp */
- /* assign to approx [round to length] */
- approxset.emin-=exp/2; /* adjust to match a */
- approxset.emax-=exp/2;
- decAddOp(a, &dzero, a, &approxset, 0, &ignore);
- }
- else {
- decAddOp(b, a, t, &workset, 0, &ignore); /* b = a + 0.5 ulp */
- workset.round=DEC_ROUND_DOWN;
- decMultiplyOp(b, b, b, &workset, &ignore); /* b = mulrd(b, b) */
- decCompareOp(b, b, f, &workset, COMPARE, &ignore); /* b ? f */
- if (decNumberIsNegative(b)) { /* b < f */
- t->exponent++; /* make 1.0 ulp */
- t->lsu[0]=1; /* .. */
- decAddOp(a, a, t, &workset, 0, &ignore); /* a = a + 1 ulp */
- /* assign to approx [round to length] */
- approxset.emin-=exp/2; /* adjust to match a */
- approxset.emax-=exp/2;
- decAddOp(a, &dzero, a, &approxset, 0, &ignore);
- }
- }
- /* [no errors are possible in the above, and rounding/inexact during */
- /* estimation are irrelevant, so status was not accumulated] */
-
- /* Here, 0.1 <= a < 1 (still), so adjust back */
- a->exponent+=exp/2; /* set correct exponent */
-
- /* count droppable zeros [after any subnormal rounding] by */
- /* trimming a copy */
- uprv_decNumberCopy(b, a);
- decTrim(b, set, 1, 1, &dropped); /* [drops trailing zeros] */
-
- /* Set Inexact and Rounded. The answer can only be exact if */
- /* it is short enough so that squaring it could fit in workp */
- /* digits, so this is the only (relatively rare) condition that */
- /* a careful check is needed */
- if (b->digits*2-1 > workp) { /* cannot fit */
- status|=DEC_Inexact|DEC_Rounded;
- }
- else { /* could be exact/unrounded */
- uInt mstatus=0; /* local status */
- decMultiplyOp(b, b, b, &workset, &mstatus); /* try the multiply */
- if (mstatus&DEC_Overflow) { /* result just won't fit */
- status|=DEC_Inexact|DEC_Rounded;
- }
- else { /* plausible */
- decCompareOp(t, b, rhs, &workset, COMPARE, &mstatus); /* b ? rhs */
- if (!ISZERO(t)) status|=DEC_Inexact|DEC_Rounded; /* not equal */
- else { /* is Exact */
- /* here, dropped is the count of trailing zeros in 'a' */
- /* use closest exponent to ideal... */
- Int todrop=ideal-a->exponent; /* most that can be dropped */
- if (todrop<0) status|=DEC_Rounded; /* ideally would add 0s */
- else { /* unrounded */
- /* there are some to drop, but emax may not allow all */
- Int maxexp=set->emax-set->digits+1;
- Int maxdrop=maxexp-a->exponent;
- if (todrop>maxdrop && set->clamp) { /* apply clamping */
- todrop=maxdrop;
- status|=DEC_Clamped;
- }
- if (dropped<todrop) { /* clamp to those available */
- todrop=dropped;
- status|=DEC_Clamped;
- }
- if (todrop>0) { /* have some to drop */
- decShiftToLeast(a->lsu, D2U(a->digits), todrop);
- a->exponent+=todrop; /* maintain numerical value */
- a->digits-=todrop; /* new length */
- }
- }
- }
- }
- }
-
- /* double-check Underflow, as perhaps the result could not have */
- /* been subnormal (initial argument too big), or it is now Exact */
- if (status&DEC_Underflow) {
- Int ae=rhs->exponent+rhs->digits-1; /* adjusted exponent */
- /* check if truly subnormal */
- #if DECEXTFLAG /* DEC_Subnormal too */
- if (ae>=set->emin*2) status&=~(DEC_Subnormal|DEC_Underflow);
- #else
- if (ae>=set->emin*2) status&=~DEC_Underflow;
- #endif
- /* check if truly inexact */
- if (!(status&DEC_Inexact)) status&=~DEC_Underflow;
- }
-
- uprv_decNumberCopy(res, a); /* a is now the result */
- } while(0); /* end protected */
-
- if (allocbuff!=NULL) free(allocbuff); /* drop any storage used */
- if (allocbufa!=NULL) free(allocbufa); /* .. */
- if (allocbufb!=NULL) free(allocbufb); /* .. */
- #if DECSUBSET
- if (allocrhs !=NULL) free(allocrhs); /* .. */
- #endif
- if (status!=0) decStatus(res, status, set);/* then report status */
- #if DECCHECK
- decCheckInexact(res, set);
- #endif
- return res;
- } /* decNumberSquareRoot */
-#if defined(__clang__) || U_GCC_MAJOR_MINOR >= 406
-#pragma GCC diagnostic pop
-#endif
-
-/* ------------------------------------------------------------------ */
-/* decNumberSubtract -- subtract two Numbers */
-/* */
-/* This computes C = A - B */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=X-X) */
-/* lhs is A */
-/* rhs is B */
-/* set is the context */
-/* */
-/* C must have space for set->digits digits. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberSubtract(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- uInt status=0; /* accumulator */
-
- decAddOp(res, lhs, rhs, set, DECNEG, &status);
- if (status!=0) decStatus(res, status, set);
- #if DECCHECK
- decCheckInexact(res, set);
- #endif
- return res;
- } /* decNumberSubtract */
-
-/* ------------------------------------------------------------------ */
-/* decNumberToIntegralExact -- round-to-integral-value with InExact */
-/* decNumberToIntegralValue -- round-to-integral-value */
-/* */
-/* res is the result */
-/* rhs is input number */
-/* set is the context */
-/* */
-/* res must have space for any value of rhs. */
-/* */
-/* This implements the IEEE special operators and therefore treats */
-/* special values as valid. For finite numbers it returns */
-/* rescale(rhs, 0) if rhs->exponent is <0. */
-/* Otherwise the result is rhs (so no error is possible, except for */
-/* sNaN). */
-/* */
-/* The context is used for rounding mode and status after sNaN, but */
-/* the digits setting is ignored. The Exact version will signal */
-/* Inexact if the result differs numerically from rhs; the other */
-/* never signals Inexact. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberToIntegralExact(decNumber *res, const decNumber *rhs,
- decContext *set) {
- decNumber dn;
- decContext workset; /* working context */
- uInt status=0; /* accumulator */
-
- #if DECCHECK
- if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
- #endif
-
- /* handle infinities and NaNs */
- if (SPECIALARG) {
- if (decNumberIsInfinite(rhs)) uprv_decNumberCopy(res, rhs); /* an Infinity */
- else decNaNs(res, rhs, NULL, set, &status); /* a NaN */
- }
- else { /* finite */
- /* have a finite number; no error possible (res must be big enough) */
- if (rhs->exponent>=0) return uprv_decNumberCopy(res, rhs);
- /* that was easy, but if negative exponent there is work to do... */
- workset=*set; /* clone rounding, etc. */
- workset.digits=rhs->digits; /* no length rounding */
- workset.traps=0; /* no traps */
- uprv_decNumberZero(&dn); /* make a number with exponent 0 */
- uprv_decNumberQuantize(res, rhs, &dn, &workset);
- status|=workset.status;
- }
- if (status!=0) decStatus(res, status, set);
- return res;
- } /* decNumberToIntegralExact */
-
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberToIntegralValue(decNumber *res, const decNumber *rhs,
- decContext *set) {
- decContext workset=*set; /* working context */
- workset.traps=0; /* no traps */
- uprv_decNumberToIntegralExact(res, rhs, &workset);
- /* this never affects set, except for sNaNs; NaN will have been set */
- /* or propagated already, so no need to call decStatus */
- set->status|=workset.status&DEC_Invalid_operation;
- return res;
- } /* decNumberToIntegralValue */
-
-/* ------------------------------------------------------------------ */
-/* decNumberXor -- XOR two Numbers, digitwise */
-/* */
-/* This computes C = A ^ B */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=X^X) */
-/* lhs is A */
-/* rhs is B */
-/* set is the context (used for result length and error report) */
-/* */
-/* C must have space for set->digits digits. */
-/* */
-/* Logical function restrictions apply (see above); a NaN is */
-/* returned with Invalid_operation if a restriction is violated. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberXor(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- const Unit *ua, *ub; /* -> operands */
- const Unit *msua, *msub; /* -> operand msus */
- Unit *uc, *msuc; /* -> result and its msu */
- Int msudigs; /* digits in res msu */
- #if DECCHECK
- if (decCheckOperands(res, lhs, rhs, set)) return res;
- #endif
-
- if (lhs->exponent!=0 || decNumberIsSpecial(lhs) || decNumberIsNegative(lhs)
- || rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) {
- decStatus(res, DEC_Invalid_operation, set);
- return res;
- }
- /* operands are valid */
- ua=lhs->lsu; /* bottom-up */
- ub=rhs->lsu; /* .. */
- uc=res->lsu; /* .. */
- msua=ua+D2U(lhs->digits)-1; /* -> msu of lhs */
- msub=ub+D2U(rhs->digits)-1; /* -> msu of rhs */
- msuc=uc+D2U(set->digits)-1; /* -> msu of result */
- msudigs=MSUDIGITS(set->digits); /* [faster than remainder] */
- for (; uc<=msuc; ua++, ub++, uc++) { /* Unit loop */
- Unit a, b; /* extract units */
- if (ua>msua) a=0;
- else a=*ua;
- if (ub>msub) b=0;
- else b=*ub;
- *uc=0; /* can now write back */
- if (a|b) { /* maybe 1 bits to examine */
- Int i, j;
- /* This loop could be unrolled and/or use BIN2BCD tables */
- for (i=0; i<DECDPUN; i++) {
- if ((a^b)&1) *uc=*uc+(Unit)powers[i]; /* effect XOR */
- j=a%10;
- a=a/10;
- j|=b%10;
- b=b/10;
- if (j>1) {
- decStatus(res, DEC_Invalid_operation, set);
- return res;
- }
- if (uc==msuc && i==msudigs-1) break; /* just did final digit */
- } /* each digit */
- } /* non-zero */
- } /* each unit */
- /* [here uc-1 is the msu of the result] */
- res->digits=decGetDigits(res->lsu, static_cast<int32_t>(uc-res->lsu));
- res->exponent=0; /* integer */
- res->bits=0; /* sign=0 */
- return res; /* [no status to set] */
- } /* decNumberXor */
-
-
-/* ================================================================== */
-/* Utility routines */
-/* ================================================================== */
-
-/* ------------------------------------------------------------------ */
-/* decNumberClass -- return the decClass of a decNumber */
-/* dn -- the decNumber to test */
-/* set -- the context to use for Emin */
-/* returns the decClass enum */
-/* ------------------------------------------------------------------ */
-enum decClass uprv_decNumberClass(const decNumber *dn, decContext *set) {
- if (decNumberIsSpecial(dn)) {
- if (decNumberIsQNaN(dn)) return DEC_CLASS_QNAN;
- if (decNumberIsSNaN(dn)) return DEC_CLASS_SNAN;
- /* must be an infinity */
- if (decNumberIsNegative(dn)) return DEC_CLASS_NEG_INF;
- return DEC_CLASS_POS_INF;
- }
- /* is finite */
- if (uprv_decNumberIsNormal(dn, set)) { /* most common */
- if (decNumberIsNegative(dn)) return DEC_CLASS_NEG_NORMAL;
- return DEC_CLASS_POS_NORMAL;
- }
- /* is subnormal or zero */
- if (decNumberIsZero(dn)) { /* most common */
- if (decNumberIsNegative(dn)) return DEC_CLASS_NEG_ZERO;
- return DEC_CLASS_POS_ZERO;
- }
- if (decNumberIsNegative(dn)) return DEC_CLASS_NEG_SUBNORMAL;
- return DEC_CLASS_POS_SUBNORMAL;
- } /* decNumberClass */
-
-/* ------------------------------------------------------------------ */
-/* decNumberClassToString -- convert decClass to a string */
-/* */
-/* eclass is a valid decClass */
-/* returns a constant string describing the class (max 13+1 chars) */
-/* ------------------------------------------------------------------ */
-const char *uprv_decNumberClassToString(enum decClass eclass) {
- if (eclass==DEC_CLASS_POS_NORMAL) return DEC_ClassString_PN;
- if (eclass==DEC_CLASS_NEG_NORMAL) return DEC_ClassString_NN;
- if (eclass==DEC_CLASS_POS_ZERO) return DEC_ClassString_PZ;
- if (eclass==DEC_CLASS_NEG_ZERO) return DEC_ClassString_NZ;
- if (eclass==DEC_CLASS_POS_SUBNORMAL) return DEC_ClassString_PS;
- if (eclass==DEC_CLASS_NEG_SUBNORMAL) return DEC_ClassString_NS;
- if (eclass==DEC_CLASS_POS_INF) return DEC_ClassString_PI;
- if (eclass==DEC_CLASS_NEG_INF) return DEC_ClassString_NI;
- if (eclass==DEC_CLASS_QNAN) return DEC_ClassString_QN;
- if (eclass==DEC_CLASS_SNAN) return DEC_ClassString_SN;
- return DEC_ClassString_UN; /* Unknown */
- } /* decNumberClassToString */
-
-/* ------------------------------------------------------------------ */
-/* decNumberCopy -- copy a number */
-/* */
-/* dest is the target decNumber */
-/* src is the source decNumber */
-/* returns dest */
-/* */
-/* (dest==src is allowed and is a no-op) */
-/* All fields are updated as required. This is a utility operation, */
-/* so special values are unchanged and no error is possible. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberCopy(decNumber *dest, const decNumber *src) {
-
- #if DECCHECK
- if (src==NULL) return uprv_decNumberZero(dest);
- #endif
-
- if (dest==src) return dest; /* no copy required */
-
- /* Use explicit assignments here as structure assignment could copy */
- /* more than just the lsu (for small DECDPUN). This would not affect */
- /* the value of the results, but could disturb test harness spill */
- /* checking. */
- dest->bits=src->bits;
- dest->exponent=src->exponent;
- dest->digits=src->digits;
- dest->lsu[0]=src->lsu[0];
- if (src->digits>DECDPUN) { /* more Units to come */
- const Unit *smsup, *s; /* work */
- Unit *d; /* .. */
- /* memcpy for the remaining Units would be safe as they cannot */
- /* overlap. However, this explicit loop is faster in short cases. */
- d=dest->lsu+1; /* -> first destination */
- smsup=src->lsu+D2U(src->digits); /* -> source msu+1 */
- for (s=src->lsu+1; s<smsup; s++, d++) *d=*s;
- }
- return dest;
- } /* decNumberCopy */
-
-/* ------------------------------------------------------------------ */
-/* decNumberCopyAbs -- quiet absolute value operator */
-/* */
-/* This sets C = abs(A) */
-/* */
-/* res is C, the result. C may be A */
-/* rhs is A */
-/* */
-/* C must have space for set->digits digits. */
-/* No exception or error can occur; this is a quiet bitwise operation.*/
-/* See also decNumberAbs for a checking version of this. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberCopyAbs(decNumber *res, const decNumber *rhs) {
- #if DECCHECK
- if (decCheckOperands(res, DECUNUSED, rhs, DECUNCONT)) return res;
- #endif
- uprv_decNumberCopy(res, rhs);
- res->bits&=~DECNEG; /* turn off sign */
- return res;
- } /* decNumberCopyAbs */
-
-/* ------------------------------------------------------------------ */
-/* decNumberCopyNegate -- quiet negate value operator */
-/* */
-/* This sets C = negate(A) */
-/* */
-/* res is C, the result. C may be A */
-/* rhs is A */
-/* */
-/* C must have space for set->digits digits. */
-/* No exception or error can occur; this is a quiet bitwise operation.*/
-/* See also decNumberMinus for a checking version of this. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberCopyNegate(decNumber *res, const decNumber *rhs) {
- #if DECCHECK
- if (decCheckOperands(res, DECUNUSED, rhs, DECUNCONT)) return res;
- #endif
- uprv_decNumberCopy(res, rhs);
- res->bits^=DECNEG; /* invert the sign */
- return res;
- } /* decNumberCopyNegate */
-
-/* ------------------------------------------------------------------ */
-/* decNumberCopySign -- quiet copy and set sign operator */
-/* */
-/* This sets C = A with the sign of B */
-/* */
-/* res is C, the result. C may be A */
-/* lhs is A */
-/* rhs is B */
-/* */
-/* C must have space for set->digits digits. */
-/* No exception or error can occur; this is a quiet bitwise operation.*/
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberCopySign(decNumber *res, const decNumber *lhs,
- const decNumber *rhs) {
- uByte sign; /* rhs sign */
- #if DECCHECK
- if (decCheckOperands(res, DECUNUSED, rhs, DECUNCONT)) return res;
- #endif
- sign=rhs->bits & DECNEG; /* save sign bit */
- uprv_decNumberCopy(res, lhs);
- res->bits&=~DECNEG; /* clear the sign */
- res->bits|=sign; /* set from rhs */
- return res;
- } /* decNumberCopySign */
-
-/* ------------------------------------------------------------------ */
-/* decNumberGetBCD -- get the coefficient in BCD8 */
-/* dn is the source decNumber */
-/* bcd is the uInt array that will receive dn->digits BCD bytes, */
-/* most-significant at offset 0 */
-/* returns bcd */
-/* */
-/* bcd must have at least dn->digits bytes. No error is possible; if */
-/* dn is a NaN or Infinite, digits must be 1 and the coefficient 0. */
-/* ------------------------------------------------------------------ */
-U_CAPI uByte * U_EXPORT2 uprv_decNumberGetBCD(const decNumber *dn, uByte *bcd) {
- uByte *ub=bcd+dn->digits-1; /* -> lsd */
- const Unit *up=dn->lsu; /* Unit pointer, -> lsu */
-
- #if DECDPUN==1 /* trivial simple copy */
- for (; ub>=bcd; ub--, up++) *ub=*up;
- #else /* chopping needed */
- uInt u=*up; /* work */
- uInt cut=DECDPUN; /* downcounter through unit */
- for (; ub>=bcd; ub--) {
- *ub=(uByte)(u%10); /* [*6554 trick inhibits, here] */
- u=u/10;
- cut--;
- if (cut>0) continue; /* more in this unit */
- up++;
- u=*up;
- cut=DECDPUN;
- }
- #endif
- return bcd;
- } /* decNumberGetBCD */
-
-/* ------------------------------------------------------------------ */
-/* decNumberSetBCD -- set (replace) the coefficient from BCD8 */
-/* dn is the target decNumber */
-/* bcd is the uInt array that will source n BCD bytes, most- */
-/* significant at offset 0 */
-/* n is the number of digits in the source BCD array (bcd) */
-/* returns dn */
-/* */
-/* dn must have space for at least n digits. No error is possible; */
-/* if dn is a NaN, or Infinite, or is to become a zero, n must be 1 */
-/* and bcd[0] zero. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberSetBCD(decNumber *dn, const uByte *bcd, uInt n) {
- Unit *up=dn->lsu+D2U(dn->digits)-1; /* -> msu [target pointer] */
- const uByte *ub=bcd; /* -> source msd */
-
- #if DECDPUN==1 /* trivial simple copy */
- for (; ub<bcd+n; ub++, up--) *up=*ub;
- #else /* some assembly needed */
- /* calculate how many digits in msu, and hence first cut */
- Int cut=MSUDIGITS(n); /* [faster than remainder] */
- for (;up>=dn->lsu; up--) { /* each Unit from msu */
- *up=0; /* will take <=DECDPUN digits */
- for (; cut>0; ub++, cut--) *up=X10(*up)+*ub;
- cut=DECDPUN; /* next Unit has all digits */
- }
- #endif
- dn->digits=n; /* set digit count */
- return dn;
- } /* decNumberSetBCD */
-
-/* ------------------------------------------------------------------ */
-/* decNumberIsNormal -- test normality of a decNumber */
-/* dn is the decNumber to test */
-/* set is the context to use for Emin */
-/* returns 1 if |dn| is finite and >=Nmin, 0 otherwise */
-/* ------------------------------------------------------------------ */
-Int uprv_decNumberIsNormal(const decNumber *dn, decContext *set) {
- Int ae; /* adjusted exponent */
- #if DECCHECK
- if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0;
- #endif
-
- if (decNumberIsSpecial(dn)) return 0; /* not finite */
- if (decNumberIsZero(dn)) return 0; /* not non-zero */
-
- ae=dn->exponent+dn->digits-1; /* adjusted exponent */
- if (ae<set->emin) return 0; /* is subnormal */
- return 1;
- } /* decNumberIsNormal */
-
-/* ------------------------------------------------------------------ */
-/* decNumberIsSubnormal -- test subnormality of a decNumber */
-/* dn is the decNumber to test */
-/* set is the context to use for Emin */
-/* returns 1 if |dn| is finite, non-zero, and <Nmin, 0 otherwise */
-/* ------------------------------------------------------------------ */
-Int uprv_decNumberIsSubnormal(const decNumber *dn, decContext *set) {
- Int ae; /* adjusted exponent */
- #if DECCHECK
- if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0;
- #endif
-
- if (decNumberIsSpecial(dn)) return 0; /* not finite */
- if (decNumberIsZero(dn)) return 0; /* not non-zero */
-
- ae=dn->exponent+dn->digits-1; /* adjusted exponent */
- if (ae<set->emin) return 1; /* is subnormal */
- return 0;
- } /* decNumberIsSubnormal */
-
-/* ------------------------------------------------------------------ */
-/* decNumberTrim -- remove insignificant zeros */
-/* */
-/* dn is the number to trim */
-/* returns dn */
-/* */
-/* All fields are updated as required. This is a utility operation, */
-/* so special values are unchanged and no error is possible. The */
-/* zeros are removed unconditionally. */
-/* ------------------------------------------------------------------ */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberTrim(decNumber *dn) {
- Int dropped; /* work */
- decContext set; /* .. */
- #if DECCHECK
- if (decCheckOperands(DECUNRESU, DECUNUSED, dn, DECUNCONT)) return dn;
- #endif
- uprv_decContextDefault(&set, DEC_INIT_BASE); /* clamp=0 */
- return decTrim(dn, &set, 0, 1, &dropped);
- } /* decNumberTrim */
-
-/* ------------------------------------------------------------------ */
-/* decNumberVersion -- return the name and version of this module */
-/* */
-/* No error is possible. */
-/* ------------------------------------------------------------------ */
-const char * uprv_decNumberVersion(void) {
- return DECVERSION;
- } /* decNumberVersion */
-
-/* ------------------------------------------------------------------ */
-/* decNumberZero -- set a number to 0 */
-/* */
-/* dn is the number to set, with space for one digit */
-/* returns dn */
-/* */
-/* No error is possible. */
-/* ------------------------------------------------------------------ */
-/* Memset is not used as it is much slower in some environments. */
-U_CAPI decNumber * U_EXPORT2 uprv_decNumberZero(decNumber *dn) {
-
- #if DECCHECK
- if (decCheckOperands(dn, DECUNUSED, DECUNUSED, DECUNCONT)) return dn;
- #endif
-
- dn->bits=0;
- dn->exponent=0;
- dn->digits=1;
- dn->lsu[0]=0;
- return dn;
- } /* decNumberZero */
-
-/* ================================================================== */
-/* Local routines */
-/* ================================================================== */
-
-/* ------------------------------------------------------------------ */
-/* decToString -- lay out a number into a string */
-/* */
-/* dn is the number to lay out */
-/* string is where to lay out the number */
-/* eng is 1 if Engineering, 0 if Scientific */
-/* */
-/* string must be at least dn->digits+14 characters long */
-/* No error is possible. */
-/* */
-/* Note that this routine can generate a -0 or 0.000. These are */
-/* never generated in subset to-number or arithmetic, but can occur */
-/* in non-subset arithmetic (e.g., -1*0 or 1.234-1.234). */
-/* ------------------------------------------------------------------ */
-/* If DECCHECK is enabled the string "?" is returned if a number is */
-/* invalid. */
-static void decToString(const decNumber *dn, char *string, Flag eng) {
- Int exp=dn->exponent; /* local copy */
- Int e; /* E-part value */
- Int pre; /* digits before the '.' */
- Int cut; /* for counting digits in a Unit */
- char *c=string; /* work [output pointer] */
- const Unit *up=dn->lsu+D2U(dn->digits)-1; /* -> msu [input pointer] */
- uInt u, pow; /* work */
-
- #if DECCHECK
- if (decCheckOperands(DECUNRESU, dn, DECUNUSED, DECUNCONT)) {
- strcpy(string, "?");
- return;}
- #endif
-
- if (decNumberIsNegative(dn)) { /* Negatives get a minus */
- *c='-';
- c++;
- }
- if (dn->bits&DECSPECIAL) { /* Is a special value */
- if (decNumberIsInfinite(dn)) {
- strcpy(c, "Inf");
- strcpy(c+3, "inity");
- return;}
- /* a NaN */
- if (dn->bits&DECSNAN) { /* signalling NaN */
- *c='s';
- c++;
- }
- strcpy(c, "NaN");
- c+=3; /* step past */
- /* if not a clean non-zero coefficient, that's all there is in a */
- /* NaN string */
- if (exp!=0 || (*dn->lsu==0 && dn->digits==1)) return;
- /* [drop through to add integer] */
- }
-
- /* calculate how many digits in msu, and hence first cut */
- cut=MSUDIGITS(dn->digits); /* [faster than remainder] */
- cut--; /* power of ten for digit */
-
- if (exp==0) { /* simple integer [common fastpath] */
- for (;up>=dn->lsu; up--) { /* each Unit from msu */
- u=*up; /* contains DECDPUN digits to lay out */
- for (; cut>=0; c++, cut--) TODIGIT(u, cut, c, pow);
- cut=DECDPUN-1; /* next Unit has all digits */
- }
- *c='\0'; /* terminate the string */
- return;}
-
- /* non-0 exponent -- assume plain form */
- pre=dn->digits+exp; /* digits before '.' */
- e=0; /* no E */
- if ((exp>0) || (pre<-5)) { /* need exponential form */
- e=exp+dn->digits-1; /* calculate E value */
- pre=1; /* assume one digit before '.' */
- if (eng && (e!=0)) { /* engineering: may need to adjust */
- Int adj; /* adjustment */
- /* The C remainder operator is undefined for negative numbers, so */
- /* a positive remainder calculation must be used here */
- if (e<0) {
- adj=(-e)%3;
- if (adj!=0) adj=3-adj;
- }
- else { /* e>0 */
- adj=e%3;
- }
- e=e-adj;
- /* if dealing with zero still produce an exponent which is a */
- /* multiple of three, as expected, but there will only be the */
- /* one zero before the E, still. Otherwise note the padding. */
- if (!ISZERO(dn)) pre+=adj;
- else { /* is zero */
- if (adj!=0) { /* 0.00Esnn needed */
- e=e+3;
- pre=-(2-adj);
- }
- } /* zero */
- } /* eng */
- } /* need exponent */
-
- /* lay out the digits of the coefficient, adding 0s and . as needed */
- u=*up;
- if (pre>0) { /* xxx.xxx or xx00 (engineering) form */
- Int n=pre;
- for (; pre>0; pre--, c++, cut--) {
- if (cut<0) { /* need new Unit */
- if (up==dn->lsu) break; /* out of input digits (pre>digits) */
- up--;
- cut=DECDPUN-1;
- u=*up;
- }
- TODIGIT(u, cut, c, pow);
- }
- if (n<dn->digits) { /* more to come, after '.' */
- *c='.'; c++;
- for (;; c++, cut--) {
- if (cut<0) { /* need new Unit */
- if (up==dn->lsu) break; /* out of input digits */
- up--;
- cut=DECDPUN-1;
- u=*up;
- }
- TODIGIT(u, cut, c, pow);
- }
- }
- else for (; pre>0; pre--, c++) *c='0'; /* 0 padding (for engineering) needed */
- }
- else { /* 0.xxx or 0.000xxx form */
- *c='0'; c++;
- *c='.'; c++;
- for (; pre<0; pre++, c++) *c='0'; /* add any 0's after '.' */
- for (; ; c++, cut--) {
- if (cut<0) { /* need new Unit */
- if (up==dn->lsu) break; /* out of input digits */
- up--;
- cut=DECDPUN-1;
- u=*up;
- }
- TODIGIT(u, cut, c, pow);
- }
- }
-
- /* Finally add the E-part, if needed. It will never be 0, has a
- base maximum and minimum of +999999999 through -999999999, but
- could range down to -1999999998 for anormal numbers */
- if (e!=0) {
- Flag had=0; /* 1=had non-zero */
- *c='E'; c++;
- *c='+'; c++; /* assume positive */
- u=e; /* .. */
- if (e<0) {
- *(c-1)='-'; /* oops, need - */
- u=-e; /* uInt, please */
- }
- /* lay out the exponent [_itoa or equivalent is not ANSI C] */
- for (cut=9; cut>=0; cut--) {
- TODIGIT(u, cut, c, pow);
- if (*c=='0' && !had) continue; /* skip leading zeros */
- had=1; /* had non-0 */
- c++; /* step for next */
- } /* cut */
- }
- *c='\0'; /* terminate the string (all paths) */
- return;
- } /* decToString */
-
-/* ------------------------------------------------------------------ */
-/* decAddOp -- add/subtract operation */
-/* */
-/* This computes C = A + B */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=X+X) */
-/* lhs is A */
-/* rhs is B */
-/* set is the context */
-/* negate is DECNEG if rhs should be negated, or 0 otherwise */
-/* status accumulates status for the caller */
-/* */
-/* C must have space for set->digits digits. */
-/* Inexact in status must be 0 for correct Exact zero sign in result */
-/* ------------------------------------------------------------------ */
-/* If possible, the coefficient is calculated directly into C. */
-/* However, if: */
-/* -- a digits+1 calculation is needed because the numbers are */
-/* unaligned and span more than set->digits digits */
-/* -- a carry to digits+1 digits looks possible */
-/* -- C is the same as A or B, and the result would destructively */
-/* overlap the A or B coefficient */
-/* then the result must be calculated into a temporary buffer. In */
-/* this case a local (stack) buffer is used if possible, and only if */
-/* too long for that does malloc become the final resort. */
-/* */
-/* Misalignment is handled as follows: */
-/* Apad: (AExp>BExp) Swap operands and proceed as for BExp>AExp. */
-/* BPad: Apply the padding by a combination of shifting (whole */
-/* units) and multiplication (part units). */
-/* */
-/* Addition, especially x=x+1, is speed-critical. */
-/* The static buffer is larger than might be expected to allow for */
-/* calls from higher-level funtions (notable exp). */
-/* ------------------------------------------------------------------ */
-static decNumber * decAddOp(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set,
- uByte negate, uInt *status) {
- #if DECSUBSET
- decNumber *alloclhs=NULL; /* non-NULL if rounded lhs allocated */
- decNumber *allocrhs=NULL; /* .., rhs */
- #endif
- Int rhsshift; /* working shift (in Units) */
- Int maxdigits; /* longest logical length */
- Int mult; /* multiplier */
- Int residue; /* rounding accumulator */
- uByte bits; /* result bits */
- Flag diffsign; /* non-0 if arguments have different sign */
- Unit *acc; /* accumulator for result */
- Unit accbuff[SD2U(DECBUFFER*2+20)]; /* local buffer [*2+20 reduces many */
- /* allocations when called from */
- /* other operations, notable exp] */
- Unit *allocacc=NULL; /* -> allocated acc buffer, iff allocated */
- Int reqdigits=set->digits; /* local copy; requested DIGITS */
- Int padding; /* work */
-
- #if DECCHECK
- if (decCheckOperands(res, lhs, rhs, set)) return res;
- #endif
-
- do { /* protect allocated storage */
- #if DECSUBSET
- if (!set->extended) {
- /* reduce operands and set lostDigits status, as needed */
- if (lhs->digits>reqdigits) {
- alloclhs=decRoundOperand(lhs, set, status);
- if (alloclhs==NULL) break;
- lhs=alloclhs;
- }
- if (rhs->digits>reqdigits) {
- allocrhs=decRoundOperand(rhs, set, status);
- if (allocrhs==NULL) break;
- rhs=allocrhs;
- }
- }
- #endif
- /* [following code does not require input rounding] */
-
- /* note whether signs differ [used all paths] */
- diffsign=(Flag)((lhs->bits^rhs->bits^negate)&DECNEG);
-
- /* handle infinities and NaNs */
- if (SPECIALARGS) { /* a special bit set */
- if (SPECIALARGS & (DECSNAN | DECNAN)) /* a NaN */
- decNaNs(res, lhs, rhs, set, status);
- else { /* one or two infinities */
- if (decNumberIsInfinite(lhs)) { /* LHS is infinity */
- /* two infinities with different signs is invalid */
- if (decNumberIsInfinite(rhs) && diffsign) {
- *status|=DEC_Invalid_operation;
- break;
- }
- bits=lhs->bits & DECNEG; /* get sign from LHS */
- }
- else bits=(rhs->bits^negate) & DECNEG;/* RHS must be Infinity */
- bits|=DECINF;
- uprv_decNumberZero(res);
- res->bits=bits; /* set +/- infinity */
- } /* an infinity */
- break;
- }
-
- /* Quick exit for add 0s; return the non-0, modified as need be */
- if (ISZERO(lhs)) {
- Int adjust; /* work */
- Int lexp=lhs->exponent; /* save in case LHS==RES */
- bits=lhs->bits; /* .. */
- residue=0; /* clear accumulator */
- decCopyFit(res, rhs, set, &residue, status); /* copy (as needed) */
- res->bits^=negate; /* flip if rhs was negated */
- #if DECSUBSET
- if (set->extended) { /* exponents on zeros count */
- #endif
- /* exponent will be the lower of the two */
- adjust=lexp-res->exponent; /* adjustment needed [if -ve] */
- if (ISZERO(res)) { /* both 0: special IEEE 754 rules */
- if (adjust<0) res->exponent=lexp; /* set exponent */
- /* 0-0 gives +0 unless rounding to -infinity, and -0-0 gives -0 */
- if (diffsign) {
- if (set->round!=DEC_ROUND_FLOOR) res->bits=0;
- else res->bits=DECNEG; /* preserve 0 sign */
- }
- }
- else { /* non-0 res */
- if (adjust<0) { /* 0-padding needed */
- if ((res->digits-adjust)>set->digits) {
- adjust=res->digits-set->digits; /* to fit exactly */
- *status|=DEC_Rounded; /* [but exact] */
- }
- res->digits=decShiftToMost(res->lsu, res->digits, -adjust);
- res->exponent+=adjust; /* set the exponent. */
- }
- } /* non-0 res */
- #if DECSUBSET
- } /* extended */
- #endif
- decFinish(res, set, &residue, status); /* clean and finalize */
- break;}
-
- if (ISZERO(rhs)) { /* [lhs is non-zero] */
- Int adjust; /* work */
- Int rexp=rhs->exponent; /* save in case RHS==RES */
- bits=rhs->bits; /* be clean */
- residue=0; /* clear accumulator */
- decCopyFit(res, lhs, set, &residue, status); /* copy (as needed) */
- #if DECSUBSET
- if (set->extended) { /* exponents on zeros count */
- #endif
- /* exponent will be the lower of the two */
- /* [0-0 case handled above] */
- adjust=rexp-res->exponent; /* adjustment needed [if -ve] */
- if (adjust<0) { /* 0-padding needed */
- if ((res->digits-adjust)>set->digits) {
- adjust=res->digits-set->digits; /* to fit exactly */
- *status|=DEC_Rounded; /* [but exact] */
- }
- res->digits=decShiftToMost(res->lsu, res->digits, -adjust);
- res->exponent+=adjust; /* set the exponent. */
- }
- #if DECSUBSET
- } /* extended */
- #endif
- decFinish(res, set, &residue, status); /* clean and finalize */
- break;}
-
- /* [NB: both fastpath and mainpath code below assume these cases */
- /* (notably 0-0) have already been handled] */
-
- /* calculate the padding needed to align the operands */
- padding=rhs->exponent-lhs->exponent;
-
- /* Fastpath cases where the numbers are aligned and normal, the RHS */
- /* is all in one unit, no operand rounding is needed, and no carry, */
- /* lengthening, or borrow is needed */
- if (padding==0
- && rhs->digits<=DECDPUN
- && rhs->exponent>=set->emin /* [some normals drop through] */
- && rhs->exponent<=set->emax-set->digits+1 /* [could clamp] */
- && rhs->digits<=reqdigits
- && lhs->digits<=reqdigits) {
- Int partial=*lhs->lsu;
- if (!diffsign) { /* adding */
- partial+=*rhs->lsu;
- if ((partial<=DECDPUNMAX) /* result fits in unit */
- && (lhs->digits>=DECDPUN || /* .. and no digits-count change */
- partial<(Int)powers[lhs->digits])) { /* .. */
- if (res!=lhs) uprv_decNumberCopy(res, lhs); /* not in place */
- *res->lsu=(Unit)partial; /* [copy could have overwritten RHS] */
- break;
- }
- /* else drop out for careful add */
- }
- else { /* signs differ */
- partial-=*rhs->lsu;
- if (partial>0) { /* no borrow needed, and non-0 result */
- if (res!=lhs) uprv_decNumberCopy(res, lhs); /* not in place */
- *res->lsu=(Unit)partial;
- /* this could have reduced digits [but result>0] */
- res->digits=decGetDigits(res->lsu, D2U(res->digits));
- break;
- }
- /* else drop out for careful subtract */
- }
- }
-
- /* Now align (pad) the lhs or rhs so they can be added or */
- /* subtracted, as necessary. If one number is much larger than */
- /* the other (that is, if in plain form there is a least one */
- /* digit between the lowest digit of one and the highest of the */
- /* other) padding with up to DIGITS-1 trailing zeros may be */
- /* needed; then apply rounding (as exotic rounding modes may be */
- /* affected by the residue). */
- rhsshift=0; /* rhs shift to left (padding) in Units */
- bits=lhs->bits; /* assume sign is that of LHS */
- mult=1; /* likely multiplier */
-
- /* [if padding==0 the operands are aligned; no padding is needed] */
- if (padding!=0) {
- /* some padding needed; always pad the RHS, as any required */
- /* padding can then be effected by a simple combination of */
- /* shifts and a multiply */
- Flag swapped=0;
- if (padding<0) { /* LHS needs the padding */
- const decNumber *t;
- padding=-padding; /* will be +ve */
- bits=(uByte)(rhs->bits^negate); /* assumed sign is now that of RHS */
- t=lhs; lhs=rhs; rhs=t;
- swapped=1;
- }
-
- /* If, after pad, rhs would be longer than lhs by digits+1 or */
- /* more then lhs cannot affect the answer, except as a residue, */
- /* so only need to pad up to a length of DIGITS+1. */
- if (rhs->digits+padding > lhs->digits+reqdigits+1) {
- /* The RHS is sufficient */
- /* for residue use the relative sign indication... */
- Int shift=reqdigits-rhs->digits; /* left shift needed */
- residue=1; /* residue for rounding */
- if (diffsign) residue=-residue; /* signs differ */
- /* copy, shortening if necessary */
- decCopyFit(res, rhs, set, &residue, status);
- /* if it was already shorter, then need to pad with zeros */
- if (shift>0) {
- res->digits=decShiftToMost(res->lsu, res->digits, shift);
- res->exponent-=shift; /* adjust the exponent. */
- }
- /* flip the result sign if unswapped and rhs was negated */
- if (!swapped) res->bits^=negate;
- decFinish(res, set, &residue, status); /* done */
- break;}
-
- /* LHS digits may affect result */
- rhsshift=D2U(padding+1)-1; /* this much by Unit shift .. */
- mult=powers[padding-(rhsshift*DECDPUN)]; /* .. this by multiplication */
- } /* padding needed */
-
- if (diffsign) mult=-mult; /* signs differ */
-
- /* determine the longer operand */
- maxdigits=rhs->digits+padding; /* virtual length of RHS */
- if (lhs->digits>maxdigits) maxdigits=lhs->digits;
-
- /* Decide on the result buffer to use; if possible place directly */
- /* into result. */
- acc=res->lsu; /* assume add direct to result */
- /* If destructive overlap, or the number is too long, or a carry or */
- /* borrow to DIGITS+1 might be possible, a buffer must be used. */
- /* [Might be worth more sophisticated tests when maxdigits==reqdigits] */
- if ((maxdigits>=reqdigits) /* is, or could be, too large */
- || (res==rhs && rhsshift>0)) { /* destructive overlap */
- /* buffer needed, choose it; units for maxdigits digits will be */
- /* needed, +1 Unit for carry or borrow */
- Int need=D2U(maxdigits)+1;
- acc=accbuff; /* assume use local buffer */
- if (need*sizeof(Unit)>sizeof(accbuff)) {
- /* printf("malloc add %ld %ld\n", need, sizeof(accbuff)); */
- allocacc=(Unit *)malloc(need*sizeof(Unit));
- if (allocacc==NULL) { /* hopeless -- abandon */
- *status|=DEC_Insufficient_storage;
- break;}
- acc=allocacc;
- }
- }
-
- res->bits=(uByte)(bits&DECNEG); /* it's now safe to overwrite.. */
- res->exponent=lhs->exponent; /* .. operands (even if aliased) */
-
- #if DECTRACE
- decDumpAr('A', lhs->lsu, D2U(lhs->digits));
- decDumpAr('B', rhs->lsu, D2U(rhs->digits));
- printf(" :h: %ld %ld\n", rhsshift, mult);
- #endif
-
- /* add [A+B*m] or subtract [A+B*(-m)] */
- U_ASSERT(rhs->digits > 0);
- U_ASSERT(lhs->digits > 0);
- res->digits=decUnitAddSub(lhs->lsu, D2U(lhs->digits),
- rhs->lsu, D2U(rhs->digits),
- rhsshift, acc, mult)
- *DECDPUN; /* [units -> digits] */
- if (res->digits<0) { /* borrowed... */
- res->digits=-res->digits;
- res->bits^=DECNEG; /* flip the sign */
- }
- #if DECTRACE
- decDumpAr('+', acc, D2U(res->digits));
- #endif
-
- /* If a buffer was used the result must be copied back, possibly */
- /* shortening. (If no buffer was used then the result must have */
- /* fit, so can't need rounding and residue must be 0.) */
- residue=0; /* clear accumulator */
- if (acc!=res->lsu) {
- #if DECSUBSET
- if (set->extended) { /* round from first significant digit */
- #endif
- /* remove leading zeros that were added due to rounding up to */
- /* integral Units -- before the test for rounding. */
- if (res->digits>reqdigits)
- res->digits=decGetDigits(acc, D2U(res->digits));
- decSetCoeff(res, set, acc, res->digits, &residue, status);
- #if DECSUBSET
- }
- else { /* subset arithmetic rounds from original significant digit */
- /* May have an underestimate. This only occurs when both */
- /* numbers fit in DECDPUN digits and are padding with a */
- /* negative multiple (-10, -100...) and the top digit(s) become */
- /* 0. (This only matters when using X3.274 rules where the */
- /* leading zero could be included in the rounding.) */
- if (res->digits<maxdigits) {
- *(acc+D2U(res->digits))=0; /* ensure leading 0 is there */
- res->digits=maxdigits;
- }
- else {
- /* remove leading zeros that added due to rounding up to */
- /* integral Units (but only those in excess of the original */
- /* maxdigits length, unless extended) before test for rounding. */
- if (res->digits>reqdigits) {
- res->digits=decGetDigits(acc, D2U(res->digits));
- if (res->digits<maxdigits) res->digits=maxdigits;
- }
- }
- decSetCoeff(res, set, acc, res->digits, &residue, status);
- /* Now apply rounding if needed before removing leading zeros. */
- /* This is safe because subnormals are not a possibility */
- if (residue!=0) {
- decApplyRound(res, set, residue, status);
- residue=0; /* did what needed to be done */
- }
- } /* subset */
- #endif
- } /* used buffer */
-
- /* strip leading zeros [these were left on in case of subset subtract] */
- res->digits=decGetDigits(res->lsu, D2U(res->digits));
-
- /* apply checks and rounding */
- decFinish(res, set, &residue, status);
-
- /* "When the sum of two operands with opposite signs is exactly */
- /* zero, the sign of that sum shall be '+' in all rounding modes */
- /* except round toward -Infinity, in which mode that sign shall be */
- /* '-'." [Subset zeros also never have '-', set by decFinish.] */
- if (ISZERO(res) && diffsign
- #if DECSUBSET
- && set->extended
- #endif
- && (*status&DEC_Inexact)==0) {
- if (set->round==DEC_ROUND_FLOOR) res->bits|=DECNEG; /* sign - */
- else res->bits&=~DECNEG; /* sign + */
- }
- } while(0); /* end protected */
-
- if (allocacc!=NULL) free(allocacc); /* drop any storage used */
- #if DECSUBSET
- if (allocrhs!=NULL) free(allocrhs); /* .. */
- if (alloclhs!=NULL) free(alloclhs); /* .. */
- #endif
- return res;
- } /* decAddOp */
-
-/* ------------------------------------------------------------------ */
-/* decDivideOp -- division operation */
-/* */
-/* This routine performs the calculations for all four division */
-/* operators (divide, divideInteger, remainder, remainderNear). */
-/* */
-/* C=A op B */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=X/X) */
-/* lhs is A */
-/* rhs is B */
-/* set is the context */
-/* op is DIVIDE, DIVIDEINT, REMAINDER, or REMNEAR respectively. */
-/* status is the usual accumulator */
-/* */
-/* C must have space for set->digits digits. */
-/* */
-/* ------------------------------------------------------------------ */
-/* The underlying algorithm of this routine is the same as in the */
-/* 1981 S/370 implementation, that is, non-restoring long division */
-/* with bi-unit (rather than bi-digit) estimation for each unit */
-/* multiplier. In this pseudocode overview, complications for the */
-/* Remainder operators and division residues for exact rounding are */
-/* omitted for clarity. */
-/* */
-/* Prepare operands and handle special values */
-/* Test for x/0 and then 0/x */
-/* Exp =Exp1 - Exp2 */
-/* Exp =Exp +len(var1) -len(var2) */
-/* Sign=Sign1 * Sign2 */
-/* Pad accumulator (Var1) to double-length with 0's (pad1) */
-/* Pad Var2 to same length as Var1 */
-/* msu2pair/plus=1st 2 or 1 units of var2, +1 to allow for round */
-/* have=0 */
-/* Do until (have=digits+1 OR residue=0) */
-/* if exp<0 then if integer divide/residue then leave */
-/* this_unit=0 */
-/* Do forever */
-/* compare numbers */
-/* if <0 then leave inner_loop */
-/* if =0 then (* quick exit without subtract *) do */
-/* this_unit=this_unit+1; output this_unit */
-/* leave outer_loop; end */
-/* Compare lengths of numbers (mantissae): */
-/* If same then tops2=msu2pair -- {units 1&2 of var2} */
-/* else tops2=msu2plus -- {0, unit 1 of var2} */
-/* tops1=first_unit_of_Var1*10**DECDPUN +second_unit_of_var1 */
-/* mult=tops1/tops2 -- Good and safe guess at divisor */
-/* if mult=0 then mult=1 */
-/* this_unit=this_unit+mult */
-/* subtract */
-/* end inner_loop */
-/* if have\=0 | this_unit\=0 then do */
-/* output this_unit */
-/* have=have+1; end */
-/* var2=var2/10 */
-/* exp=exp-1 */
-/* end outer_loop */
-/* exp=exp+1 -- set the proper exponent */
-/* if have=0 then generate answer=0 */
-/* Return (Result is defined by Var1) */
-/* */
-/* ------------------------------------------------------------------ */
-/* Two working buffers are needed during the division; one (digits+ */
-/* 1) to accumulate the result, and the other (up to 2*digits+1) for */
-/* long subtractions. These are acc and var1 respectively. */
-/* var1 is a copy of the lhs coefficient, var2 is the rhs coefficient.*/
-/* The static buffers may be larger than might be expected to allow */
-/* for calls from higher-level funtions (notable exp). */
-/* ------------------------------------------------------------------ */
-static decNumber * decDivideOp(decNumber *res,
- const decNumber *lhs, const decNumber *rhs,
- decContext *set, Flag op, uInt *status) {
- #if DECSUBSET
- decNumber *alloclhs=NULL; /* non-NULL if rounded lhs allocated */
- decNumber *allocrhs=NULL; /* .., rhs */
- #endif
- Unit accbuff[SD2U(DECBUFFER+DECDPUN+10)]; /* local buffer */
- Unit *acc=accbuff; /* -> accumulator array for result */
- Unit *allocacc=NULL; /* -> allocated buffer, iff allocated */
- Unit *accnext; /* -> where next digit will go */
- Int acclength; /* length of acc needed [Units] */
- Int accunits; /* count of units accumulated */
- Int accdigits; /* count of digits accumulated */
-
- Unit varbuff[SD2U(DECBUFFER*2+DECDPUN)]; /* buffer for var1 */
- Unit *var1=varbuff; /* -> var1 array for long subtraction */
- Unit *varalloc=NULL; /* -> allocated buffer, iff used */
- Unit *msu1; /* -> msu of var1 */
-
- const Unit *var2; /* -> var2 array */
- const Unit *msu2; /* -> msu of var2 */
- Int msu2plus; /* msu2 plus one [does not vary] */
- eInt msu2pair; /* msu2 pair plus one [does not vary] */
-
- Int var1units, var2units; /* actual lengths */
- Int var2ulen; /* logical length (units) */
- Int var1initpad=0; /* var1 initial padding (digits) */
- Int maxdigits; /* longest LHS or required acc length */
- Int mult; /* multiplier for subtraction */
- Unit thisunit; /* current unit being accumulated */
- Int residue; /* for rounding */
- Int reqdigits=set->digits; /* requested DIGITS */
- Int exponent; /* working exponent */
- Int maxexponent=0; /* DIVIDE maximum exponent if unrounded */
- uByte bits; /* working sign */
- Unit *target; /* work */
- const Unit *source; /* .. */
- uInt const *pow; /* .. */
- Int shift, cut; /* .. */
- #if DECSUBSET
- Int dropped; /* work */
- #endif
-
- #if DECCHECK
- if (decCheckOperands(res, lhs, rhs, set)) return res;
- #endif
-
- do { /* protect allocated storage */
- #if DECSUBSET
- if (!set->extended) {
- /* reduce operands and set lostDigits status, as needed */
- if (lhs->digits>reqdigits) {
- alloclhs=decRoundOperand(lhs, set, status);
- if (alloclhs==NULL) break;
- lhs=alloclhs;
- }
- if (rhs->digits>reqdigits) {
- allocrhs=decRoundOperand(rhs, set, status);
- if (allocrhs==NULL) break;
- rhs=allocrhs;
- }
- }
- #endif
- /* [following code does not require input rounding] */
-
- bits=(lhs->bits^rhs->bits)&DECNEG; /* assumed sign for divisions */
-
- /* handle infinities and NaNs */
- if (SPECIALARGS) { /* a special bit set */
- if (SPECIALARGS & (DECSNAN | DECNAN)) { /* one or two NaNs */
- decNaNs(res, lhs, rhs, set, status);
- break;
- }
- /* one or two infinities */
- if (decNumberIsInfinite(lhs)) { /* LHS (dividend) is infinite */
- if (decNumberIsInfinite(rhs) || /* two infinities are invalid .. */
- op & (REMAINDER | REMNEAR)) { /* as is remainder of infinity */
- *status|=DEC_Invalid_operation;
- break;
- }
- /* [Note that infinity/0 raises no exceptions] */
- uprv_decNumberZero(res);
- res->bits=bits|DECINF; /* set +/- infinity */
- break;
- }
- else { /* RHS (divisor) is infinite */
- residue=0;
- if (op&(REMAINDER|REMNEAR)) {
- /* result is [finished clone of] lhs */
- decCopyFit(res, lhs, set, &residue, status);
- }
- else { /* a division */
- uprv_decNumberZero(res);
- res->bits=bits; /* set +/- zero */
- /* for DIVIDEINT the exponent is always 0. For DIVIDE, result */
- /* is a 0 with infinitely negative exponent, clamped to minimum */
- if (op&DIVIDE) {
- res->exponent=set->emin-set->digits+1;
- *status|=DEC_Clamped;
- }
- }
- decFinish(res, set, &residue, status);
- break;
- }
- }
-
- /* handle 0 rhs (x/0) */
- if (ISZERO(rhs)) { /* x/0 is always exceptional */
- if (ISZERO(lhs)) {
- uprv_decNumberZero(res); /* [after lhs test] */
- *status|=DEC_Division_undefined;/* 0/0 will become NaN */
- }
- else {
- uprv_decNumberZero(res);
- if (op&(REMAINDER|REMNEAR)) *status|=DEC_Invalid_operation;
- else {
- *status|=DEC_Division_by_zero; /* x/0 */
- res->bits=bits|DECINF; /* .. is +/- Infinity */
- }
- }
- break;}
-
- /* handle 0 lhs (0/x) */
- if (ISZERO(lhs)) { /* 0/x [x!=0] */
- #if DECSUBSET
- if (!set->extended) uprv_decNumberZero(res);
- else {
- #endif
- if (op&DIVIDE) {
- residue=0;
- exponent=lhs->exponent-rhs->exponent; /* ideal exponent */
- uprv_decNumberCopy(res, lhs); /* [zeros always fit] */
- res->bits=bits; /* sign as computed */
- res->exponent=exponent; /* exponent, too */
- decFinalize(res, set, &residue, status); /* check exponent */
- }
- else if (op&DIVIDEINT) {
- uprv_decNumberZero(res); /* integer 0 */
- res->bits=bits; /* sign as computed */
- }
- else { /* a remainder */
- exponent=rhs->exponent; /* [save in case overwrite] */
- uprv_decNumberCopy(res, lhs); /* [zeros always fit] */
- if (exponent<res->exponent) res->exponent=exponent; /* use lower */
- }
- #if DECSUBSET
- }
- #endif
- break;}
-
- /* Precalculate exponent. This starts off adjusted (and hence fits */
- /* in 31 bits) and becomes the usual unadjusted exponent as the */
- /* division proceeds. The order of evaluation is important, here, */
- /* to avoid wrap. */
- exponent=(lhs->exponent+lhs->digits)-(rhs->exponent+rhs->digits);
-
- /* If the working exponent is -ve, then some quick exits are */
- /* possible because the quotient is known to be <1 */
- /* [for REMNEAR, it needs to be < -1, as -0.5 could need work] */
- if (exponent<0 && !(op==DIVIDE)) {
- if (op&DIVIDEINT) {
- uprv_decNumberZero(res); /* integer part is 0 */
- #if DECSUBSET
- if (set->extended)
- #endif
- res->bits=bits; /* set +/- zero */
- break;}
- /* fastpath remainders so long as the lhs has the smaller */
- /* (or equal) exponent */
- if (lhs->exponent<=rhs->exponent) {
- if (op&REMAINDER || exponent<-1) {
- /* It is REMAINDER or safe REMNEAR; result is [finished */
- /* clone of] lhs (r = x - 0*y) */
- residue=0;
- decCopyFit(res, lhs, set, &residue, status);
- decFinish(res, set, &residue, status);
- break;
- }
- /* [unsafe REMNEAR drops through] */
- }
- } /* fastpaths */
-
- /* Long (slow) division is needed; roll up the sleeves... */
-
- /* The accumulator will hold the quotient of the division. */
- /* If it needs to be too long for stack storage, then allocate. */
- acclength=D2U(reqdigits+DECDPUN); /* in Units */
- if (acclength*sizeof(Unit)>sizeof(accbuff)) {
- /* printf("malloc dvacc %ld units\n", acclength); */
- allocacc=(Unit *)malloc(acclength*sizeof(Unit));
- if (allocacc==NULL) { /* hopeless -- abandon */
- *status|=DEC_Insufficient_storage;
- break;}
- acc=allocacc; /* use the allocated space */
- }
-
- /* var1 is the padded LHS ready for subtractions. */
- /* If it needs to be too long for stack storage, then allocate. */
- /* The maximum units needed for var1 (long subtraction) is: */
- /* Enough for */
- /* (rhs->digits+reqdigits-1) -- to allow full slide to right */
- /* or (lhs->digits) -- to allow for long lhs */
- /* whichever is larger */
- /* +1 -- for rounding of slide to right */
- /* +1 -- for leading 0s */
- /* +1 -- for pre-adjust if a remainder or DIVIDEINT */
- /* [Note: unused units do not participate in decUnitAddSub data] */
- maxdigits=rhs->digits+reqdigits-1;
- if (lhs->digits>maxdigits) maxdigits=lhs->digits;
- var1units=D2U(maxdigits)+2;
- /* allocate a guard unit above msu1 for REMAINDERNEAR */
- if (!(op&DIVIDE)) var1units++;
- if ((var1units+1)*sizeof(Unit)>sizeof(varbuff)) {
- /* printf("malloc dvvar %ld units\n", var1units+1); */
- varalloc=(Unit *)malloc((var1units+1)*sizeof(Unit));
- if (varalloc==NULL) { /* hopeless -- abandon */
- *status|=DEC_Insufficient_storage;
- break;}
- var1=varalloc; /* use the allocated space */
- }
-
- /* Extend the lhs and rhs to full long subtraction length. The lhs */
- /* is truly extended into the var1 buffer, with 0 padding, so a */
- /* subtract in place is always possible. The rhs (var2) has */
- /* virtual padding (implemented by decUnitAddSub). */
- /* One guard unit was allocated above msu1 for rem=rem+rem in */
- /* REMAINDERNEAR. */
- msu1=var1+var1units-1; /* msu of var1 */
- source=lhs->lsu+D2U(lhs->digits)-1; /* msu of input array */
- for (target=msu1; source>=lhs->lsu; source--, target--) *target=*source;
- for (; target>=var1; target--) *target=0;
-
- /* rhs (var2) is left-aligned with var1 at the start */
- var2ulen=var1units; /* rhs logical length (units) */
- var2units=D2U(rhs->digits); /* rhs actual length (units) */
- var2=rhs->lsu; /* -> rhs array */
- msu2=var2+var2units-1; /* -> msu of var2 [never changes] */
- /* now set up the variables which will be used for estimating the */
- /* multiplication factor. If these variables are not exact, add */
- /* 1 to make sure that the multiplier is never overestimated. */
- msu2plus=*msu2; /* it's value .. */
- if (var2units>1) msu2plus++; /* .. +1 if any more */
- msu2pair=(eInt)*msu2*(DECDPUNMAX+1);/* top two pair .. */
- if (var2units>1) { /* .. [else treat 2nd as 0] */
- msu2pair+=*(msu2-1); /* .. */
- if (var2units>2) msu2pair++; /* .. +1 if any more */
- }
-
- /* The calculation is working in units, which may have leading zeros, */
- /* but the exponent was calculated on the assumption that they are */
- /* both left-aligned. Adjust the exponent to compensate: add the */
- /* number of leading zeros in var1 msu and subtract those in var2 msu. */
- /* [This is actually done by counting the digits and negating, as */
- /* lead1=DECDPUN-digits1, and similarly for lead2.] */
- for (pow=&powers[1]; *msu1>=*pow; pow++) exponent--;
- for (pow=&powers[1]; *msu2>=*pow; pow++) exponent++;
-
- /* Now, if doing an integer divide or remainder, ensure that */
- /* the result will be Unit-aligned. To do this, shift the var1 */
- /* accumulator towards least if need be. (It's much easier to */
- /* do this now than to reassemble the residue afterwards, if */
- /* doing a remainder.) Also ensure the exponent is not negative. */
- if (!(op&DIVIDE)) {
- Unit *u; /* work */
- /* save the initial 'false' padding of var1, in digits */
- var1initpad=(var1units-D2U(lhs->digits))*DECDPUN;
- /* Determine the shift to do. */
- if (exponent<0) cut=-exponent;
- else cut=DECDPUN-exponent%DECDPUN;
- decShiftToLeast(var1, var1units, cut);
- exponent+=cut; /* maintain numerical value */
- var1initpad-=cut; /* .. and reduce padding */
- /* clean any most-significant units which were just emptied */
- for (u=msu1; cut>=DECDPUN; cut-=DECDPUN, u--) *u=0;
- } /* align */
- else { /* is DIVIDE */
- maxexponent=lhs->exponent-rhs->exponent; /* save */
- /* optimization: if the first iteration will just produce 0, */
- /* preadjust to skip it [valid for DIVIDE only] */
- if (*msu1<*msu2) {
- var2ulen--; /* shift down */
- exponent-=DECDPUN; /* update the exponent */
- }
- }
-
- /* ---- start the long-division loops ------------------------------ */
- accunits=0; /* no units accumulated yet */
- accdigits=0; /* .. or digits */
- accnext=acc+acclength-1; /* -> msu of acc [NB: allows digits+1] */
- for (;;) { /* outer forever loop */
- thisunit=0; /* current unit assumed 0 */
- /* find the next unit */
- for (;;) { /* inner forever loop */
- /* strip leading zero units [from either pre-adjust or from */
- /* subtract last time around]. Leave at least one unit. */
- for (; *msu1==0 && msu1>var1; msu1--) var1units--;
-
- if (var1units<var2ulen) break; /* var1 too low for subtract */
- if (var1units==var2ulen) { /* unit-by-unit compare needed */
- /* compare the two numbers, from msu */
- const Unit *pv1, *pv2;
- Unit v2; /* units to compare */
- pv2=msu2; /* -> msu */
- for (pv1=msu1; ; pv1--, pv2--) {
- /* v1=*pv1 -- always OK */
- v2=0; /* assume in padding */
- if (pv2>=var2) v2=*pv2; /* in range */
- if (*pv1!=v2) break; /* no longer the same */
- if (pv1==var1) break; /* done; leave pv1 as is */
- }
- /* here when all inspected or a difference seen */
- if (*pv1<v2) break; /* var1 too low to subtract */
- if (*pv1==v2) { /* var1 == var2 */
- /* reach here if var1 and var2 are identical; subtraction */
- /* would increase digit by one, and the residue will be 0 so */
- /* the calculation is done; leave the loop with residue=0. */
- thisunit++; /* as though subtracted */
- *var1=0; /* set var1 to 0 */
- var1units=1; /* .. */
- break; /* from inner */
- } /* var1 == var2 */
- /* *pv1>v2. Prepare for real subtraction; the lengths are equal */
- /* Estimate the multiplier (there's always a msu1-1)... */
- /* Bring in two units of var2 to provide a good estimate. */
- mult=(Int)(((eInt)*msu1*(DECDPUNMAX+1)+*(msu1-1))/msu2pair);
- } /* lengths the same */
- else { /* var1units > var2ulen, so subtraction is safe */
- /* The var2 msu is one unit towards the lsu of the var1 msu, */
- /* so only one unit for var2 can be used. */
- mult=(Int)(((eInt)*msu1*(DECDPUNMAX+1)+*(msu1-1))/msu2plus);
- }
- if (mult==0) mult=1; /* must always be at least 1 */
- /* subtraction needed; var1 is > var2 */
- thisunit=(Unit)(thisunit+mult); /* accumulate */
- /* subtract var1-var2, into var1; only the overlap needs */
- /* processing, as this is an in-place calculation */
- shift=var2ulen-var2units;
- #if DECTRACE
- decDumpAr('1', &var1[shift], var1units-shift);
- decDumpAr('2', var2, var2units);
- printf("m=%ld\n", -mult);
- #endif
- decUnitAddSub(&var1[shift], var1units-shift,
- var2, var2units, 0,
- &var1[shift], -mult);
- #if DECTRACE
- decDumpAr('#', &var1[shift], var1units-shift);
- #endif
- /* var1 now probably has leading zeros; these are removed at the */
- /* top of the inner loop. */
- } /* inner loop */
-
- /* The next unit has been calculated in full; unless it's a */
- /* leading zero, add to acc */
- if (accunits!=0 || thisunit!=0) { /* is first or non-zero */
- *accnext=thisunit; /* store in accumulator */
- /* account exactly for the new digits */
- if (accunits==0) {
- accdigits++; /* at least one */
- for (pow=&powers[1]; thisunit>=*pow; pow++) accdigits++;
- }
- else accdigits+=DECDPUN;
- accunits++; /* update count */
- accnext--; /* ready for next */
- if (accdigits>reqdigits) break; /* have enough digits */
- }
-
- /* if the residue is zero, the operation is done (unless divide */
- /* or divideInteger and still not enough digits yet) */
- if (*var1==0 && var1units==1) { /* residue is 0 */
- if (op&(REMAINDER|REMNEAR)) break;
- if ((op&DIVIDE) && (exponent<=maxexponent)) break;
- /* [drop through if divideInteger] */
- }
- /* also done enough if calculating remainder or integer */
- /* divide and just did the last ('units') unit */
- if (exponent==0 && !(op&DIVIDE)) break;
-
- /* to get here, var1 is less than var2, so divide var2 by the per- */
- /* Unit power of ten and go for the next digit */
- var2ulen--; /* shift down */
- exponent-=DECDPUN; /* update the exponent */
- } /* outer loop */
-
- /* ---- division is complete --------------------------------------- */
- /* here: acc has at least reqdigits+1 of good results (or fewer */
- /* if early stop), starting at accnext+1 (its lsu) */
- /* var1 has any residue at the stopping point */
- /* accunits is the number of digits collected in acc */
- if (accunits==0) { /* acc is 0 */
- accunits=1; /* show have a unit .. */
- accdigits=1; /* .. */
- *accnext=0; /* .. whose value is 0 */
- }
- else accnext++; /* back to last placed */
- /* accnext now -> lowest unit of result */
-
- residue=0; /* assume no residue */
- if (op&DIVIDE) {
- /* record the presence of any residue, for rounding */
- if (*var1!=0 || var1units>1) residue=1;
- else { /* no residue */
- /* Had an exact division; clean up spurious trailing 0s. */
- /* There will be at most DECDPUN-1, from the final multiply, */
- /* and then only if the result is non-0 (and even) and the */
- /* exponent is 'loose'. */
- #if DECDPUN>1
- Unit lsu=*accnext;
- if (!(lsu&0x01) && (lsu!=0)) {
- /* count the trailing zeros */
- Int drop=0;
- for (;; drop++) { /* [will terminate because lsu!=0] */
- if (exponent>=maxexponent) break; /* don't chop real 0s */
- #if DECDPUN<=4
- if ((lsu-QUOT10(lsu, drop+1)
- *powers[drop+1])!=0) break; /* found non-0 digit */
- #else
- if (lsu%powers[drop+1]!=0) break; /* found non-0 digit */
- #endif
- exponent++;
- }
- if (drop>0) {
- accunits=decShiftToLeast(accnext, accunits, drop);
- accdigits=decGetDigits(accnext, accunits);
- accunits=D2U(accdigits);
- /* [exponent was adjusted in the loop] */
- }
- } /* neither odd nor 0 */
- #endif
- } /* exact divide */
- } /* divide */
- else /* op!=DIVIDE */ {
- /* check for coefficient overflow */
- if (accdigits+exponent>reqdigits) {
- *status|=DEC_Division_impossible;
- break;
- }
- if (op & (REMAINDER|REMNEAR)) {
- /* [Here, the exponent will be 0, because var1 was adjusted */
- /* appropriately.] */
- Int postshift; /* work */
- Flag wasodd=0; /* integer was odd */
- Unit *quotlsu; /* for save */
- Int quotdigits; /* .. */
-
- bits=lhs->bits; /* remainder sign is always as lhs */
-
- /* Fastpath when residue is truly 0 is worthwhile [and */
- /* simplifies the code below] */
- if (*var1==0 && var1units==1) { /* residue is 0 */
- Int exp=lhs->exponent; /* save min(exponents) */
- if (rhs->exponent<exp) exp=rhs->exponent;
- uprv_decNumberZero(res); /* 0 coefficient */
- #if DECSUBSET
- if (set->extended)
- #endif
- res->exponent=exp; /* .. with proper exponent */
- res->bits=(uByte)(bits&DECNEG); /* [cleaned] */
- decFinish(res, set, &residue, status); /* might clamp */
- break;
- }
- /* note if the quotient was odd */
- if (*accnext & 0x01) wasodd=1; /* acc is odd */
- quotlsu=accnext; /* save in case need to reinspect */
- quotdigits=accdigits; /* .. */
-
- /* treat the residue, in var1, as the value to return, via acc */
- /* calculate the unused zero digits. This is the smaller of: */
- /* var1 initial padding (saved above) */
- /* var2 residual padding, which happens to be given by: */
- postshift=var1initpad+exponent-lhs->exponent+rhs->exponent;
- /* [the 'exponent' term accounts for the shifts during divide] */
- if (var1initpad<postshift) postshift=var1initpad;
-
- /* shift var1 the requested amount, and adjust its digits */
- var1units=decShiftToLeast(var1, var1units, postshift);
- accnext=var1;
- accdigits=decGetDigits(var1, var1units);
- accunits=D2U(accdigits);
-
- exponent=lhs->exponent; /* exponent is smaller of lhs & rhs */
- if (rhs->exponent<exponent) exponent=rhs->exponent;
-
- /* Now correct the result if doing remainderNear; if it */
- /* (looking just at coefficients) is > rhs/2, or == rhs/2 and */
- /* the integer was odd then the result should be rem-rhs. */
- if (op&REMNEAR) {
- Int compare, tarunits; /* work */
- Unit *up; /* .. */
- /* calculate remainder*2 into the var1 buffer (which has */
- /* 'headroom' of an extra unit and hence enough space) */
- /* [a dedicated 'double' loop would be faster, here] */
- tarunits=decUnitAddSub(accnext, accunits, accnext, accunits,
- 0, accnext, 1);
- /* decDumpAr('r', accnext, tarunits); */
-
- /* Here, accnext (var1) holds tarunits Units with twice the */
- /* remainder's coefficient, which must now be compared to the */
- /* RHS. The remainder's exponent may be smaller than the RHS's. */
- compare=decUnitCompare(accnext, tarunits, rhs->lsu, D2U(rhs->digits),
- rhs->exponent-exponent);
- if (compare==BADINT) { /* deep trouble */
- *status|=DEC_Insufficient_storage;
- break;}
-
- /* now restore the remainder by dividing by two; the lsu */
- /* is known to be even. */
- for (up=accnext; up<accnext+tarunits; up++) {
- Int half; /* half to add to lower unit */
- half=*up & 0x01;
- *up/=2; /* [shift] */
- if (!half) continue;
- *(up-1)+=(DECDPUNMAX+1)/2;
- }
- /* [accunits still describes the original remainder length] */
-
- if (compare>0 || (compare==0 && wasodd)) { /* adjustment needed */
- Int exp, expunits, exprem; /* work */
- /* This is effectively causing round-up of the quotient, */
- /* so if it was the rare case where it was full and all */
- /* nines, it would overflow and hence division-impossible */
- /* should be raised */
- Flag allnines=0; /* 1 if quotient all nines */
- if (quotdigits==reqdigits) { /* could be borderline */
- for (up=quotlsu; ; up++) {
- if (quotdigits>DECDPUN) {
- if (*up!=DECDPUNMAX) break;/* non-nines */
- }
- else { /* this is the last Unit */
- if (*up==powers[quotdigits]-1) allnines=1;
- break;
- }
- quotdigits-=DECDPUN; /* checked those digits */
- } /* up */
- } /* borderline check */
- if (allnines) {
- *status|=DEC_Division_impossible;
- break;}
-
- /* rem-rhs is needed; the sign will invert. Again, var1 */
- /* can safely be used for the working Units array. */
- exp=rhs->exponent-exponent; /* RHS padding needed */
- /* Calculate units and remainder from exponent. */
- expunits=exp/DECDPUN;
- exprem=exp%DECDPUN;
- /* subtract [A+B*(-m)]; the result will always be negative */
- accunits=-decUnitAddSub(accnext, accunits,
- rhs->lsu, D2U(rhs->digits),
- expunits, accnext, -(Int)powers[exprem]);
- accdigits=decGetDigits(accnext, accunits); /* count digits exactly */
- accunits=D2U(accdigits); /* and recalculate the units for copy */
- /* [exponent is as for original remainder] */
- bits^=DECNEG; /* flip the sign */
- }
- } /* REMNEAR */
- } /* REMAINDER or REMNEAR */
- } /* not DIVIDE */
-
- /* Set exponent and bits */
- res->exponent=exponent;
- res->bits=(uByte)(bits&DECNEG); /* [cleaned] */
-
- /* Now the coefficient. */
- decSetCoeff(res, set, accnext, accdigits, &residue, status);
-
- decFinish(res, set, &residue, status); /* final cleanup */
-
- #if DECSUBSET
- /* If a divide then strip trailing zeros if subset [after round] */
- if (!set->extended && (op==DIVIDE)) decTrim(res, set, 0, 1, &dropped);
- #endif
- } while(0); /* end protected */
-
- if (varalloc!=NULL) free(varalloc); /* drop any storage used */
- if (allocacc!=NULL) free(allocacc); /* .. */
- #if DECSUBSET
- if (allocrhs!=NULL) free(allocrhs); /* .. */
- if (alloclhs!=NULL) free(alloclhs); /* .. */
- #endif
- return res;
- } /* decDivideOp */
-
-/* ------------------------------------------------------------------ */
-/* decMultiplyOp -- multiplication operation */
-/* */
-/* This routine performs the multiplication C=A x B. */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=X*X) */
-/* lhs is A */
-/* rhs is B */
-/* set is the context */
-/* status is the usual accumulator */
-/* */
-/* C must have space for set->digits digits. */
-/* */
-/* ------------------------------------------------------------------ */
-/* 'Classic' multiplication is used rather than Karatsuba, as the */
-/* latter would give only a minor improvement for the short numbers */
-/* expected to be handled most (and uses much more memory). */
-/* */
-/* There are two major paths here: the general-purpose ('old code') */
-/* path which handles all DECDPUN values, and a fastpath version */
-/* which is used if 64-bit ints are available, DECDPUN<=4, and more */
-/* than two calls to decUnitAddSub would be made. */
-/* */
-/* The fastpath version lumps units together into 8-digit or 9-digit */
-/* chunks, and also uses a lazy carry strategy to minimise expensive */
-/* 64-bit divisions. The chunks are then broken apart again into */
-/* units for continuing processing. Despite this overhead, the */
-/* fastpath can speed up some 16-digit operations by 10x (and much */
-/* more for higher-precision calculations). */
-/* */
-/* A buffer always has to be used for the accumulator; in the */
-/* fastpath, buffers are also always needed for the chunked copies of */
-/* of the operand coefficients. */
-/* Static buffers are larger than needed just for multiply, to allow */
-/* for calls from other operations (notably exp). */
-/* ------------------------------------------------------------------ */
-#define FASTMUL (DECUSE64 && DECDPUN<5)
-static decNumber * decMultiplyOp(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set,
- uInt *status) {
- Int accunits; /* Units of accumulator in use */
- Int exponent; /* work */
- Int residue=0; /* rounding residue */
- uByte bits; /* result sign */
- Unit *acc; /* -> accumulator Unit array */
- Int needbytes; /* size calculator */
- void *allocacc=NULL; /* -> allocated accumulator, iff allocated */
- Unit accbuff[SD2U(DECBUFFER*4+1)]; /* buffer (+1 for DECBUFFER==0, */
- /* *4 for calls from other operations) */
- const Unit *mer, *mermsup; /* work */
- Int madlength; /* Units in multiplicand */
- Int shift; /* Units to shift multiplicand by */
-
- #if FASTMUL
- /* if DECDPUN is 1 or 3 work in base 10**9, otherwise */
- /* (DECDPUN is 2 or 4) then work in base 10**8 */
- #if DECDPUN & 1 /* odd */
- #define FASTBASE 1000000000 /* base */
- #define FASTDIGS 9 /* digits in base */
- #define FASTLAZY 18 /* carry resolution point [1->18] */
- #else
- #define FASTBASE 100000000
- #define FASTDIGS 8
- #define FASTLAZY 1844 /* carry resolution point [1->1844] */
- #endif
- /* three buffers are used, two for chunked copies of the operands */
- /* (base 10**8 or base 10**9) and one base 2**64 accumulator with */
- /* lazy carry evaluation */
- uInt zlhibuff[(DECBUFFER*2+1)/8+1]; /* buffer (+1 for DECBUFFER==0) */
- uInt *zlhi=zlhibuff; /* -> lhs array */
- uInt *alloclhi=NULL; /* -> allocated buffer, iff allocated */
- uInt zrhibuff[(DECBUFFER*2+1)/8+1]; /* buffer (+1 for DECBUFFER==0) */
- uInt *zrhi=zrhibuff; /* -> rhs array */
- uInt *allocrhi=NULL; /* -> allocated buffer, iff allocated */
- uLong zaccbuff[(DECBUFFER*2+1)/4+2]; /* buffer (+1 for DECBUFFER==0) */
- /* [allocacc is shared for both paths, as only one will run] */
- uLong *zacc=zaccbuff; /* -> accumulator array for exact result */
- #if DECDPUN==1
- Int zoff; /* accumulator offset */
- #endif
- uInt *lip, *rip; /* item pointers */
- uInt *lmsi, *rmsi; /* most significant items */
- Int ilhs, irhs, iacc; /* item counts in the arrays */
- Int lazy; /* lazy carry counter */
- uLong lcarry; /* uLong carry */
- uInt carry; /* carry (NB not uLong) */
- Int count; /* work */
- const Unit *cup; /* .. */
- Unit *up; /* .. */
- uLong *lp; /* .. */
- Int p; /* .. */
- #endif
-
- #if DECSUBSET
- decNumber *alloclhs=NULL; /* -> allocated buffer, iff allocated */
- decNumber *allocrhs=NULL; /* -> allocated buffer, iff allocated */
- #endif
-
- #if DECCHECK
- if (decCheckOperands(res, lhs, rhs, set)) return res;
- #endif
-
- /* precalculate result sign */
- bits=(uByte)((lhs->bits^rhs->bits)&DECNEG);
-
- /* handle infinities and NaNs */
- if (SPECIALARGS) { /* a special bit set */
- if (SPECIALARGS & (DECSNAN | DECNAN)) { /* one or two NaNs */
- decNaNs(res, lhs, rhs, set, status);
- return res;}
- /* one or two infinities; Infinity * 0 is invalid */
- if (((lhs->bits & DECINF)==0 && ISZERO(lhs))
- ||((rhs->bits & DECINF)==0 && ISZERO(rhs))) {
- *status|=DEC_Invalid_operation;
- return res;}
- uprv_decNumberZero(res);
- res->bits=bits|DECINF; /* infinity */
- return res;}
-
- /* For best speed, as in DMSRCN [the original Rexx numerics */
- /* module], use the shorter number as the multiplier (rhs) and */
- /* the longer as the multiplicand (lhs) to minimise the number of */
- /* adds (partial products) */
- if (lhs->digits<rhs->digits) { /* swap... */
- const decNumber *hold=lhs;
- lhs=rhs;
- rhs=hold;
- }
-
- do { /* protect allocated storage */
- #if DECSUBSET
- if (!set->extended) {
- /* reduce operands and set lostDigits status, as needed */
- if (lhs->digits>set->digits) {
- alloclhs=decRoundOperand(lhs, set, status);
- if (alloclhs==NULL) break;
- lhs=alloclhs;
- }
- if (rhs->digits>set->digits) {
- allocrhs=decRoundOperand(rhs, set, status);
- if (allocrhs==NULL) break;
- rhs=allocrhs;
- }
- }
- #endif
- /* [following code does not require input rounding] */
-
- #if FASTMUL /* fastpath can be used */
- /* use the fast path if there are enough digits in the shorter */
- /* operand to make the setup and takedown worthwhile */
- #define NEEDTWO (DECDPUN*2) /* within two decUnitAddSub calls */
- if (rhs->digits>NEEDTWO) { /* use fastpath... */
- /* calculate the number of elements in each array */
- ilhs=(lhs->digits+FASTDIGS-1)/FASTDIGS; /* [ceiling] */
- irhs=(rhs->digits+FASTDIGS-1)/FASTDIGS; /* .. */
- iacc=ilhs+irhs;
-
- /* allocate buffers if required, as usual */
- needbytes=ilhs*sizeof(uInt);
- if (needbytes>(Int)sizeof(zlhibuff)) {
- alloclhi=(uInt *)malloc(needbytes);
- zlhi=alloclhi;}
- needbytes=irhs*sizeof(uInt);
- if (needbytes>(Int)sizeof(zrhibuff)) {
- allocrhi=(uInt *)malloc(needbytes);
- zrhi=allocrhi;}
-
- /* Allocating the accumulator space needs a special case when */
- /* DECDPUN=1 because when converting the accumulator to Units */
- /* after the multiplication each 8-byte item becomes 9 1-byte */
- /* units. Therefore iacc extra bytes are needed at the front */
- /* (rounded up to a multiple of 8 bytes), and the uLong */
- /* accumulator starts offset the appropriate number of units */
- /* to the right to avoid overwrite during the unchunking. */
-
- /* Make sure no signed int overflow below. This is always true */
- /* if the given numbers have less digits than DEC_MAX_DIGITS. */
- U_ASSERT((uint32_t)iacc <= INT32_MAX/sizeof(uLong));
- needbytes=iacc*sizeof(uLong);
- #if DECDPUN==1
- zoff=(iacc+7)/8; /* items to offset by */
- needbytes+=zoff*8;
- #endif
- if (needbytes>(Int)sizeof(zaccbuff)) {
- allocacc=(uLong *)malloc(needbytes);
- zacc=(uLong *)allocacc;}
- if (zlhi==NULL||zrhi==NULL||zacc==NULL) {
- *status|=DEC_Insufficient_storage;
- break;}
-
- acc=(Unit *)zacc; /* -> target Unit array */
- #if DECDPUN==1
- zacc+=zoff; /* start uLong accumulator to right */
- #endif
-
- /* assemble the chunked copies of the left and right sides */
- for (count=lhs->digits, cup=lhs->lsu, lip=zlhi; count>0; lip++)
- for (p=0, *lip=0; p<FASTDIGS && count>0;
- p+=DECDPUN, cup++, count-=DECDPUN)
- *lip+=*cup*powers[p];
- lmsi=lip-1; /* save -> msi */
- for (count=rhs->digits, cup=rhs->lsu, rip=zrhi; count>0; rip++)
- for (p=0, *rip=0; p<FASTDIGS && count>0;
- p+=DECDPUN, cup++, count-=DECDPUN)
- *rip+=*cup*powers[p];
- rmsi=rip-1; /* save -> msi */
-
- /* zero the accumulator */
- for (lp=zacc; lp<zacc+iacc; lp++) *lp=0;
-
- /* Start the multiplication */
- /* Resolving carries can dominate the cost of accumulating the */
- /* partial products, so this is only done when necessary. */
- /* Each uLong item in the accumulator can hold values up to */
- /* 2**64-1, and each partial product can be as large as */
- /* (10**FASTDIGS-1)**2. When FASTDIGS=9, this can be added to */
- /* itself 18.4 times in a uLong without overflowing, so during */
- /* the main calculation resolution is carried out every 18th */
- /* add -- every 162 digits. Similarly, when FASTDIGS=8, the */
- /* partial products can be added to themselves 1844.6 times in */
- /* a uLong without overflowing, so intermediate carry */
- /* resolution occurs only every 14752 digits. Hence for common */
- /* short numbers usually only the one final carry resolution */
- /* occurs. */
- /* (The count is set via FASTLAZY to simplify experiments to */
- /* measure the value of this approach: a 35% improvement on a */
- /* [34x34] multiply.) */
- lazy=FASTLAZY; /* carry delay count */
- for (rip=zrhi; rip<=rmsi; rip++) { /* over each item in rhs */
- lp=zacc+(rip-zrhi); /* where to add the lhs */
- for (lip=zlhi; lip<=lmsi; lip++, lp++) { /* over each item in lhs */
- *lp+=(uLong)(*lip)*(*rip); /* [this should in-line] */
- } /* lip loop */
- lazy--;
- if (lazy>0 && rip!=rmsi) continue;
- lazy=FASTLAZY; /* reset delay count */
- /* spin up the accumulator resolving overflows */
- for (lp=zacc; lp<zacc+iacc; lp++) {
- if (*lp<FASTBASE) continue; /* it fits */
- lcarry=*lp/FASTBASE; /* top part [slow divide] */
- /* lcarry can exceed 2**32-1, so check again; this check */
- /* and occasional extra divide (slow) is well worth it, as */
- /* it allows FASTLAZY to be increased to 18 rather than 4 */
- /* in the FASTDIGS=9 case */
- if (lcarry<FASTBASE) carry=(uInt)lcarry; /* [usual] */
- else { /* two-place carry [fairly rare] */
- uInt carry2=(uInt)(lcarry/FASTBASE); /* top top part */
- *(lp+2)+=carry2; /* add to item+2 */
- *lp-=((uLong)FASTBASE*FASTBASE*carry2); /* [slow] */
- carry=(uInt)(lcarry-((uLong)FASTBASE*carry2)); /* [inline] */
- }
- *(lp+1)+=carry; /* add to item above [inline] */
- *lp-=((uLong)FASTBASE*carry); /* [inline] */
- } /* carry resolution */
- } /* rip loop */
-
- /* The multiplication is complete; time to convert back into */
- /* units. This can be done in-place in the accumulator and in */
- /* 32-bit operations, because carries were resolved after the */
- /* final add. This needs N-1 divides and multiplies for */
- /* each item in the accumulator (which will become up to N */
- /* units, where 2<=N<=9). */
- for (lp=zacc, up=acc; lp<zacc+iacc; lp++) {
- uInt item=(uInt)*lp; /* decapitate to uInt */
- for (p=0; p<FASTDIGS-DECDPUN; p+=DECDPUN, up++) {
- uInt part=item/(DECDPUNMAX+1);
- *up=(Unit)(item-(part*(DECDPUNMAX+1)));
- item=part;
- } /* p */
- *up=(Unit)item; up++; /* [final needs no division] */
- } /* lp */
- accunits = static_cast<int32_t>(up-acc); /* count of units */
- }
- else { /* here to use units directly, without chunking ['old code'] */
- #endif
-
- /* if accumulator will be too long for local storage, then allocate */
- acc=accbuff; /* -> assume buffer for accumulator */
- needbytes=(D2U(lhs->digits)+D2U(rhs->digits))*sizeof(Unit);
- if (needbytes>(Int)sizeof(accbuff)) {
- allocacc=(Unit *)malloc(needbytes);
- if (allocacc==NULL) {*status|=DEC_Insufficient_storage; break;}
- acc=(Unit *)allocacc; /* use the allocated space */
- }
-
- /* Now the main long multiplication loop */
- /* Unlike the equivalent in the IBM Java implementation, there */
- /* is no advantage in calculating from msu to lsu. So, do it */
- /* by the book, as it were. */
- /* Each iteration calculates ACC=ACC+MULTAND*MULT */
- accunits=1; /* accumulator starts at '0' */
- *acc=0; /* .. (lsu=0) */
- shift=0; /* no multiplicand shift at first */
- madlength=D2U(lhs->digits); /* this won't change */
- mermsup=rhs->lsu+D2U(rhs->digits); /* -> msu+1 of multiplier */
-
- for (mer=rhs->lsu; mer<mermsup; mer++) {
- /* Here, *mer is the next Unit in the multiplier to use */
- /* If non-zero [optimization] add it... */
- if (*mer!=0) accunits=decUnitAddSub(&acc[shift], accunits-shift,
- lhs->lsu, madlength, 0,
- &acc[shift], *mer)
- + shift;
- else { /* extend acc with a 0; it will be used shortly */
- *(acc+accunits)=0; /* [this avoids length of <=0 later] */
- accunits++;
- }
- /* multiply multiplicand by 10**DECDPUN for next Unit to left */
- shift++; /* add this for 'logical length' */
- } /* n */
- #if FASTMUL
- } /* unchunked units */
- #endif
- /* common end-path */
- #if DECTRACE
- decDumpAr('*', acc, accunits); /* Show exact result */
- #endif
-
- /* acc now contains the exact result of the multiplication, */
- /* possibly with a leading zero unit; build the decNumber from */
- /* it, noting if any residue */
- res->bits=bits; /* set sign */
- res->digits=decGetDigits(acc, accunits); /* count digits exactly */
-
- /* There can be a 31-bit wrap in calculating the exponent. */
- /* This can only happen if both input exponents are negative and */
- /* both their magnitudes are large. If there was a wrap, set a */
- /* safe very negative exponent, from which decFinalize() will */
- /* raise a hard underflow shortly. */
- exponent=lhs->exponent+rhs->exponent; /* calculate exponent */
- if (lhs->exponent<0 && rhs->exponent<0 && exponent>0)
- exponent=-2*DECNUMMAXE; /* force underflow */
- res->exponent=exponent; /* OK to overwrite now */
-
-
- /* Set the coefficient. If any rounding, residue records */
- decSetCoeff(res, set, acc, res->digits, &residue, status);
- decFinish(res, set, &residue, status); /* final cleanup */
- } while(0); /* end protected */
-
- if (allocacc!=NULL) free(allocacc); /* drop any storage used */
- #if DECSUBSET
- if (allocrhs!=NULL) free(allocrhs); /* .. */
- if (alloclhs!=NULL) free(alloclhs); /* .. */
- #endif
- #if FASTMUL
- if (allocrhi!=NULL) free(allocrhi); /* .. */
- if (alloclhi!=NULL) free(alloclhi); /* .. */
- #endif
- return res;
- } /* decMultiplyOp */
-
-/* ------------------------------------------------------------------ */
-/* decExpOp -- effect exponentiation */
-/* */
-/* This computes C = exp(A) */
-/* */
-/* res is C, the result. C may be A */
-/* rhs is A */
-/* set is the context; note that rounding mode has no effect */
-/* */
-/* C must have space for set->digits digits. status is updated but */
-/* not set. */
-/* */
-/* Restrictions: */
-/* */
-/* digits, emax, and -emin in the context must be less than */
-/* 2*DEC_MAX_MATH (1999998), and the rhs must be within these */
-/* bounds or a zero. This is an internal routine, so these */
-/* restrictions are contractual and not enforced. */
-/* */
-/* A finite result is rounded using DEC_ROUND_HALF_EVEN; it will */
-/* almost always be correctly rounded, but may be up to 1 ulp in */
-/* error in rare cases. */
-/* */
-/* Finite results will always be full precision and Inexact, except */
-/* when A is a zero or -Infinity (giving 1 or 0 respectively). */
-/* ------------------------------------------------------------------ */
-/* This approach used here is similar to the algorithm described in */
-/* */
-/* Variable Precision Exponential Function, T. E. Hull and */
-/* A. Abrham, ACM Transactions on Mathematical Software, Vol 12 #2, */
-/* pp79-91, ACM, June 1986. */
-/* */
-/* with the main difference being that the iterations in the series */
-/* evaluation are terminated dynamically (which does not require the */
-/* extra variable-precision variables which are expensive in this */
-/* context). */
-/* */
-/* The error analysis in Hull & Abrham's paper applies except for the */
-/* round-off error accumulation during the series evaluation. This */
-/* code does not precalculate the number of iterations and so cannot */
-/* use Horner's scheme. Instead, the accumulation is done at double- */
-/* precision, which ensures that the additions of the terms are exact */
-/* and do not accumulate round-off (and any round-off errors in the */
-/* terms themselves move 'to the right' faster than they can */
-/* accumulate). This code also extends the calculation by allowing, */
-/* in the spirit of other decNumber operators, the input to be more */
-/* precise than the result (the precision used is based on the more */
-/* precise of the input or requested result). */
-/* */
-/* Implementation notes: */
-/* */
-/* 1. This is separated out as decExpOp so it can be called from */
-/* other Mathematical functions (notably Ln) with a wider range */
-/* than normal. In particular, it can handle the slightly wider */
-/* (double) range needed by Ln (which has to be able to calculate */
-/* exp(-x) where x can be the tiniest number (Ntiny). */
-/* */
-/* 2. Normalizing x to be <=0.1 (instead of <=1) reduces loop */
-/* iterations by appoximately a third with additional (although */
-/* diminishing) returns as the range is reduced to even smaller */
-/* fractions. However, h (the power of 10 used to correct the */
-/* result at the end, see below) must be kept <=8 as otherwise */
-/* the final result cannot be computed. Hence the leverage is a */
-/* sliding value (8-h), where potentially the range is reduced */
-/* more for smaller values. */
-/* */
-/* The leverage that can be applied in this way is severely */
-/* limited by the cost of the raise-to-the power at the end, */
-/* which dominates when the number of iterations is small (less */
-/* than ten) or when rhs is short. As an example, the adjustment */
-/* x**10,000,000 needs 31 multiplications, all but one full-width. */
-/* */
-/* 3. The restrictions (especially precision) could be raised with */
-/* care, but the full decNumber range seems very hard within the */
-/* 32-bit limits. */
-/* */
-/* 4. The working precisions for the static buffers are twice the */
-/* obvious size to allow for calls from decNumberPower. */
-/* ------------------------------------------------------------------ */
-decNumber * decExpOp(decNumber *res, const decNumber *rhs,
- decContext *set, uInt *status) {
- uInt ignore=0; /* working status */
- Int h; /* adjusted exponent for 0.xxxx */
- Int p; /* working precision */
- Int residue; /* rounding residue */
- uInt needbytes; /* for space calculations */
- const decNumber *x=rhs; /* (may point to safe copy later) */
- decContext aset, tset, dset; /* working contexts */
- Int comp; /* work */
-
- /* the argument is often copied to normalize it, so (unusually) it */
- /* is treated like other buffers, using DECBUFFER, +1 in case */
- /* DECBUFFER is 0 */
- decNumber bufr[D2N(DECBUFFER*2+1)];
- decNumber *allocrhs=NULL; /* non-NULL if rhs buffer allocated */
-
- /* the working precision will be no more than set->digits+8+1 */
- /* so for on-stack buffers DECBUFFER+9 is used, +1 in case DECBUFFER */
- /* is 0 (and twice that for the accumulator) */
-
- /* buffer for t, term (working precision plus) */
- decNumber buft[D2N(DECBUFFER*2+9+1)];
- decNumber *allocbuft=NULL; /* -> allocated buft, iff allocated */
- decNumber *t=buft; /* term */
- /* buffer for a, accumulator (working precision * 2), at least 9 */
- decNumber bufa[D2N(DECBUFFER*4+18+1)];
- decNumber *allocbufa=NULL; /* -> allocated bufa, iff allocated */
- decNumber *a=bufa; /* accumulator */
- /* decNumber for the divisor term; this needs at most 9 digits */
- /* and so can be fixed size [16 so can use standard context] */
- decNumber bufd[D2N(16)];
- decNumber *d=bufd; /* divisor */
- decNumber numone; /* constant 1 */
-
- #if DECCHECK
- Int iterations=0; /* for later sanity check */
- if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
- #endif
-
- do { /* protect allocated storage */
- if (SPECIALARG) { /* handle infinities and NaNs */
- if (decNumberIsInfinite(rhs)) { /* an infinity */
- if (decNumberIsNegative(rhs)) /* -Infinity -> +0 */
- uprv_decNumberZero(res);
- else uprv_decNumberCopy(res, rhs); /* +Infinity -> self */
- }
- else decNaNs(res, rhs, NULL, set, status); /* a NaN */
- break;}
-
- if (ISZERO(rhs)) { /* zeros -> exact 1 */
- uprv_decNumberZero(res); /* make clean 1 */
- *res->lsu=1; /* .. */
- break;} /* [no status to set] */
-
- /* e**x when 0 < x < 0.66 is < 1+3x/2, hence can fast-path */
- /* positive and negative tiny cases which will result in inexact */
- /* 1. This also allows the later add-accumulate to always be */
- /* exact (because its length will never be more than twice the */
- /* working precision). */
- /* The comparator (tiny) needs just one digit, so use the */
- /* decNumber d for it (reused as the divisor, etc., below); its */
- /* exponent is such that if x is positive it will have */
- /* set->digits-1 zeros between the decimal point and the digit, */
- /* which is 4, and if x is negative one more zero there as the */
- /* more precise result will be of the form 0.9999999 rather than */
- /* 1.0000001. Hence, tiny will be 0.0000004 if digits=7 and x>0 */
- /* or 0.00000004 if digits=7 and x<0. If RHS not larger than */
- /* this then the result will be 1.000000 */
- uprv_decNumberZero(d); /* clean */
- *d->lsu=4; /* set 4 .. */
- d->exponent=-set->digits; /* * 10**(-d) */
- if (decNumberIsNegative(rhs)) d->exponent--; /* negative case */
- comp=decCompare(d, rhs, 1); /* signless compare */
- if (comp==BADINT) {
- *status|=DEC_Insufficient_storage;
- break;}
- if (comp>=0) { /* rhs < d */
- Int shift=set->digits-1;
- uprv_decNumberZero(res); /* set 1 */
- *res->lsu=1; /* .. */
- res->digits=decShiftToMost(res->lsu, 1, shift);
- res->exponent=-shift; /* make 1.0000... */
- *status|=DEC_Inexact | DEC_Rounded; /* .. inexactly */
- break;} /* tiny */
-
- /* set up the context to be used for calculating a, as this is */
- /* used on both paths below */
- uprv_decContextDefault(&aset, DEC_INIT_DECIMAL64);
- /* accumulator bounds are as requested (could underflow) */
- aset.emax=set->emax; /* usual bounds */
- aset.emin=set->emin; /* .. */
- aset.clamp=0; /* and no concrete format */
-
- /* calculate the adjusted (Hull & Abrham) exponent (where the */
- /* decimal point is just to the left of the coefficient msd) */
- h=rhs->exponent+rhs->digits;
- /* if h>8 then 10**h cannot be calculated safely; however, when */
- /* h=8 then exp(|rhs|) will be at least exp(1E+7) which is at */
- /* least 6.59E+4342944, so (due to the restriction on Emax/Emin) */
- /* overflow (or underflow to 0) is guaranteed -- so this case can */
- /* be handled by simply forcing the appropriate excess */
- if (h>8) { /* overflow/underflow */
- /* set up here so Power call below will over or underflow to */
- /* zero; set accumulator to either 2 or 0.02 */
- /* [stack buffer for a is always big enough for this] */
- uprv_decNumberZero(a);
- *a->lsu=2; /* not 1 but < exp(1) */
- if (decNumberIsNegative(rhs)) a->exponent=-2; /* make 0.02 */
- h=8; /* clamp so 10**h computable */
- p=9; /* set a working precision */
- }
- else { /* h<=8 */
- Int maxlever=(rhs->digits>8?1:0);
- /* [could/should increase this for precisions >40 or so, too] */
-
- /* if h is 8, cannot normalize to a lower upper limit because */
- /* the final result will not be computable (see notes above), */
- /* but leverage can be applied whenever h is less than 8. */
- /* Apply as much as possible, up to a MAXLEVER digits, which */
- /* sets the tradeoff against the cost of the later a**(10**h). */
- /* As h is increased, the working precision below also */
- /* increases to compensate for the "constant digits at the */
- /* front" effect. */
- Int lever=MINI(8-h, maxlever); /* leverage attainable */
- Int use=-rhs->digits-lever; /* exponent to use for RHS */
- h+=lever; /* apply leverage selected */
- if (h<0) { /* clamp */
- use+=h; /* [may end up subnormal] */
- h=0;
- }
- /* Take a copy of RHS if it needs normalization (true whenever x>=1) */
- if (rhs->exponent!=use) {
- decNumber *newrhs=bufr; /* assume will fit on stack */
- needbytes=sizeof(decNumber)+(D2U(rhs->digits)-1)*sizeof(Unit);
- if (needbytes>sizeof(bufr)) { /* need malloc space */
- allocrhs=(decNumber *)malloc(needbytes);
- if (allocrhs==NULL) { /* hopeless -- abandon */
- *status|=DEC_Insufficient_storage;
- break;}
- newrhs=allocrhs; /* use the allocated space */
- }
- uprv_decNumberCopy(newrhs, rhs); /* copy to safe space */
- newrhs->exponent=use; /* normalize; now <1 */
- x=newrhs; /* ready for use */
- /* decNumberShow(x); */
- }
-
- /* Now use the usual power series to evaluate exp(x). The */
- /* series starts as 1 + x + x^2/2 ... so prime ready for the */
- /* third term by setting the term variable t=x, the accumulator */
- /* a=1, and the divisor d=2. */
-
- /* First determine the working precision. From Hull & Abrham */
- /* this is set->digits+h+2. However, if x is 'over-precise' we */
- /* need to allow for all its digits to potentially participate */
- /* (consider an x where all the excess digits are 9s) so in */
- /* this case use x->digits+h+2 */
- p=MAXI(x->digits, set->digits)+h+2; /* [h<=8] */
-
- /* a and t are variable precision, and depend on p, so space */
- /* must be allocated for them if necessary */
-
- /* the accumulator needs to be able to hold 2p digits so that */
- /* the additions on the second and subsequent iterations are */
- /* sufficiently exact. */
- needbytes=sizeof(decNumber)+(D2U(p*2)-1)*sizeof(Unit);
- if (needbytes>sizeof(bufa)) { /* need malloc space */
- allocbufa=(decNumber *)malloc(needbytes);
- if (allocbufa==NULL) { /* hopeless -- abandon */
- *status|=DEC_Insufficient_storage;
- break;}
- a=allocbufa; /* use the allocated space */
- }
- /* the term needs to be able to hold p digits (which is */
- /* guaranteed to be larger than x->digits, so the initial copy */
- /* is safe); it may also be used for the raise-to-power */
- /* calculation below, which needs an extra two digits */
- needbytes=sizeof(decNumber)+(D2U(p+2)-1)*sizeof(Unit);
- if (needbytes>sizeof(buft)) { /* need malloc space */
- allocbuft=(decNumber *)malloc(needbytes);
- if (allocbuft==NULL) { /* hopeless -- abandon */
- *status|=DEC_Insufficient_storage;
- break;}
- t=allocbuft; /* use the allocated space */
- }
-
- uprv_decNumberCopy(t, x); /* term=x */
- uprv_decNumberZero(a); *a->lsu=1; /* accumulator=1 */
- uprv_decNumberZero(d); *d->lsu=2; /* divisor=2 */
- uprv_decNumberZero(&numone); *numone.lsu=1; /* constant 1 for increment */
-
- /* set up the contexts for calculating a, t, and d */
- uprv_decContextDefault(&tset, DEC_INIT_DECIMAL64);
- dset=tset;
- /* accumulator bounds are set above, set precision now */
- aset.digits=p*2; /* double */
- /* term bounds avoid any underflow or overflow */
- tset.digits=p;
- tset.emin=DEC_MIN_EMIN; /* [emax is plenty] */
- /* [dset.digits=16, etc., are sufficient] */
-
- /* finally ready to roll */
- for (;;) {
- #if DECCHECK
- iterations++;
- #endif
- /* only the status from the accumulation is interesting */
- /* [but it should remain unchanged after first add] */
- decAddOp(a, a, t, &aset, 0, status); /* a=a+t */
- decMultiplyOp(t, t, x, &tset, &ignore); /* t=t*x */
- decDivideOp(t, t, d, &tset, DIVIDE, &ignore); /* t=t/d */
- /* the iteration ends when the term cannot affect the result, */
- /* if rounded to p digits, which is when its value is smaller */
- /* than the accumulator by p+1 digits. There must also be */
- /* full precision in a. */
- if (((a->digits+a->exponent)>=(t->digits+t->exponent+p+1))
- && (a->digits>=p)) break;
- decAddOp(d, d, &numone, &dset, 0, &ignore); /* d=d+1 */
- } /* iterate */
-
- #if DECCHECK
- /* just a sanity check; comment out test to show always */
- if (iterations>p+3)
- printf("Exp iterations=%ld, status=%08lx, p=%ld, d=%ld\n",
- (LI)iterations, (LI)*status, (LI)p, (LI)x->digits);
- #endif
- } /* h<=8 */
-
- /* apply postconditioning: a=a**(10**h) -- this is calculated */
- /* at a slightly higher precision than Hull & Abrham suggest */
- if (h>0) {
- Int seenbit=0; /* set once a 1-bit is seen */
- Int i; /* counter */
- Int n=powers[h]; /* always positive */
- aset.digits=p+2; /* sufficient precision */
- /* avoid the overhead and many extra digits of decNumberPower */
- /* as all that is needed is the short 'multipliers' loop; here */
- /* accumulate the answer into t */
- uprv_decNumberZero(t); *t->lsu=1; /* acc=1 */
- for (i=1;;i++){ /* for each bit [top bit ignored] */
- /* abandon if have had overflow or terminal underflow */
- if (*status & (DEC_Overflow|DEC_Underflow)) { /* interesting? */
- if (*status&DEC_Overflow || ISZERO(t)) break;}
- n=n<<1; /* move next bit to testable position */
- if (n<0) { /* top bit is set */
- seenbit=1; /* OK, have a significant bit */
- decMultiplyOp(t, t, a, &aset, status); /* acc=acc*x */
- }
- if (i==31) break; /* that was the last bit */
- if (!seenbit) continue; /* no need to square 1 */
- decMultiplyOp(t, t, t, &aset, status); /* acc=acc*acc [square] */
- } /*i*/ /* 32 bits */
- /* decNumberShow(t); */
- a=t; /* and carry on using t instead of a */
- }
-
- /* Copy and round the result to res */
- residue=1; /* indicate dirt to right .. */
- if (ISZERO(a)) residue=0; /* .. unless underflowed to 0 */
- aset.digits=set->digits; /* [use default rounding] */
- decCopyFit(res, a, &aset, &residue, status); /* copy & shorten */
- decFinish(res, set, &residue, status); /* cleanup/set flags */
- } while(0); /* end protected */
-
- if (allocrhs !=NULL) free(allocrhs); /* drop any storage used */
- if (allocbufa!=NULL) free(allocbufa); /* .. */
- if (allocbuft!=NULL) free(allocbuft); /* .. */
- /* [status is handled by caller] */
- return res;
- } /* decExpOp */
-
-/* ------------------------------------------------------------------ */
-/* Initial-estimate natural logarithm table */
-/* */
-/* LNnn -- 90-entry 16-bit table for values from .10 through .99. */
-/* The result is a 4-digit encode of the coefficient (c=the */
-/* top 14 bits encoding 0-9999) and a 2-digit encode of the */
-/* exponent (e=the bottom 2 bits encoding 0-3) */
-/* */
-/* The resulting value is given by: */
-/* */
-/* v = -c * 10**(-e-3) */
-/* */
-/* where e and c are extracted from entry k = LNnn[x-10] */
-/* where x is truncated (NB) into the range 10 through 99, */
-/* and then c = k>>2 and e = k&3. */
-/* ------------------------------------------------------------------ */
-static const uShort LNnn[90]={9016, 8652, 8316, 8008, 7724, 7456, 7208,
- 6972, 6748, 6540, 6340, 6148, 5968, 5792, 5628, 5464, 5312,
- 5164, 5020, 4884, 4748, 4620, 4496, 4376, 4256, 4144, 4032,
- 39233, 38181, 37157, 36157, 35181, 34229, 33297, 32389, 31501, 30629,
- 29777, 28945, 28129, 27329, 26545, 25777, 25021, 24281, 23553, 22837,
- 22137, 21445, 20769, 20101, 19445, 18801, 18165, 17541, 16925, 16321,
- 15721, 15133, 14553, 13985, 13421, 12865, 12317, 11777, 11241, 10717,
- 10197, 9685, 9177, 8677, 8185, 7697, 7213, 6737, 6269, 5801,
- 5341, 4889, 4437, 39930, 35534, 31186, 26886, 22630, 18418, 14254,
- 10130, 6046, 20055};
-
-/* ------------------------------------------------------------------ */
-/* decLnOp -- effect natural logarithm */
-/* */
-/* This computes C = ln(A) */
-/* */
-/* res is C, the result. C may be A */
-/* rhs is A */
-/* set is the context; note that rounding mode has no effect */
-/* */
-/* C must have space for set->digits digits. */
-/* */
-/* Notable cases: */
-/* A<0 -> Invalid */
-/* A=0 -> -Infinity (Exact) */
-/* A=+Infinity -> +Infinity (Exact) */
-/* A=1 exactly -> 0 (Exact) */
-/* */
-/* Restrictions (as for Exp): */
-/* */
-/* digits, emax, and -emin in the context must be less than */
-/* DEC_MAX_MATH+11 (1000010), and the rhs must be within these */
-/* bounds or a zero. This is an internal routine, so these */
-/* restrictions are contractual and not enforced. */
-/* */
-/* A finite result is rounded using DEC_ROUND_HALF_EVEN; it will */
-/* almost always be correctly rounded, but may be up to 1 ulp in */
-/* error in rare cases. */
-/* ------------------------------------------------------------------ */
-/* The result is calculated using Newton's method, with each */
-/* iteration calculating a' = a + x * exp(-a) - 1. See, for example, */
-/* Epperson 1989. */
-/* */
-/* The iteration ends when the adjustment x*exp(-a)-1 is tiny enough. */
-/* This has to be calculated at the sum of the precision of x and the */
-/* working precision. */
-/* */
-/* Implementation notes: */
-/* */
-/* 1. This is separated out as decLnOp so it can be called from */
-/* other Mathematical functions (e.g., Log 10) with a wider range */
-/* than normal. In particular, it can handle the slightly wider */
-/* (+9+2) range needed by a power function. */
-/* */
-/* 2. The speed of this function is about 10x slower than exp, as */
-/* it typically needs 4-6 iterations for short numbers, and the */
-/* extra precision needed adds a squaring effect, twice. */
-/* */
-/* 3. Fastpaths are included for ln(10) and ln(2), up to length 40, */
-/* as these are common requests. ln(10) is used by log10(x). */
-/* */
-/* 4. An iteration might be saved by widening the LNnn table, and */
-/* would certainly save at least one if it were made ten times */
-/* bigger, too (for truncated fractions 0.100 through 0.999). */
-/* However, for most practical evaluations, at least four or five */
-/* iterations will be neede -- so this would only speed up by */
-/* 20-25% and that probably does not justify increasing the table */
-/* size. */
-/* */
-/* 5. The static buffers are larger than might be expected to allow */
-/* for calls from decNumberPower. */
-/* ------------------------------------------------------------------ */
-#if defined(__clang__) || U_GCC_MAJOR_MINOR >= 406
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Warray-bounds"
-#endif
-decNumber * decLnOp(decNumber *res, const decNumber *rhs,
- decContext *set, uInt *status) {
- uInt ignore=0; /* working status accumulator */
- uInt needbytes; /* for space calculations */
- Int residue; /* rounding residue */
- Int r; /* rhs=f*10**r [see below] */
- Int p; /* working precision */
- Int pp; /* precision for iteration */
- Int t; /* work */
-
- /* buffers for a (accumulator, typically precision+2) and b */
- /* (adjustment calculator, same size) */
- decNumber bufa[D2N(DECBUFFER+12)];
- decNumber *allocbufa=NULL; /* -> allocated bufa, iff allocated */
- decNumber *a=bufa; /* accumulator/work */
- decNumber bufb[D2N(DECBUFFER*2+2)];
- decNumber *allocbufb=NULL; /* -> allocated bufa, iff allocated */
- decNumber *b=bufb; /* adjustment/work */
-
- decNumber numone; /* constant 1 */
- decNumber cmp; /* work */
- decContext aset, bset; /* working contexts */
-
- #if DECCHECK
- Int iterations=0; /* for later sanity check */
- if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
- #endif
-
- do { /* protect allocated storage */
- if (SPECIALARG) { /* handle infinities and NaNs */
- if (decNumberIsInfinite(rhs)) { /* an infinity */
- if (decNumberIsNegative(rhs)) /* -Infinity -> error */
- *status|=DEC_Invalid_operation;
- else uprv_decNumberCopy(res, rhs); /* +Infinity -> self */
- }
- else decNaNs(res, rhs, NULL, set, status); /* a NaN */
- break;}
-
- if (ISZERO(rhs)) { /* +/- zeros -> -Infinity */
- uprv_decNumberZero(res); /* make clean */
- res->bits=DECINF|DECNEG; /* set - infinity */
- break;} /* [no status to set] */
-
- /* Non-zero negatives are bad... */
- if (decNumberIsNegative(rhs)) { /* -x -> error */
- *status|=DEC_Invalid_operation;
- break;}
-
- /* Here, rhs is positive, finite, and in range */
-
- /* lookaside fastpath code for ln(2) and ln(10) at common lengths */
- if (rhs->exponent==0 && set->digits<=40) {
- #if DECDPUN==1
- if (rhs->lsu[0]==0 && rhs->lsu[1]==1 && rhs->digits==2) { /* ln(10) */
- #else
- if (rhs->lsu[0]==10 && rhs->digits==2) { /* ln(10) */
- #endif
- aset=*set; aset.round=DEC_ROUND_HALF_EVEN;
- #define LN10 "2.302585092994045684017991454684364207601"
- uprv_decNumberFromString(res, LN10, &aset);
- *status|=(DEC_Inexact | DEC_Rounded); /* is inexact */
- break;}
- if (rhs->lsu[0]==2 && rhs->digits==1) { /* ln(2) */
- aset=*set; aset.round=DEC_ROUND_HALF_EVEN;
- #define LN2 "0.6931471805599453094172321214581765680755"
- uprv_decNumberFromString(res, LN2, &aset);
- *status|=(DEC_Inexact | DEC_Rounded);
- break;}
- } /* integer and short */
-
- /* Determine the working precision. This is normally the */
- /* requested precision + 2, with a minimum of 9. However, if */
- /* the rhs is 'over-precise' then allow for all its digits to */
- /* potentially participate (consider an rhs where all the excess */
- /* digits are 9s) so in this case use rhs->digits+2. */
- p=MAXI(rhs->digits, MAXI(set->digits, 7))+2;
-
- /* Allocate space for the accumulator and the high-precision */
- /* adjustment calculator, if necessary. The accumulator must */
- /* be able to hold p digits, and the adjustment up to */
- /* rhs->digits+p digits. They are also made big enough for 16 */
- /* digits so that they can be used for calculating the initial */
- /* estimate. */
- needbytes=sizeof(decNumber)+(D2U(MAXI(p,16))-1)*sizeof(Unit);
- if (needbytes>sizeof(bufa)) { /* need malloc space */
- allocbufa=(decNumber *)malloc(needbytes);
- if (allocbufa==NULL) { /* hopeless -- abandon */
- *status|=DEC_Insufficient_storage;
- break;}
- a=allocbufa; /* use the allocated space */
- }
- pp=p+rhs->digits;
- needbytes=sizeof(decNumber)+(D2U(MAXI(pp,16))-1)*sizeof(Unit);
- if (needbytes>sizeof(bufb)) { /* need malloc space */
- allocbufb=(decNumber *)malloc(needbytes);
- if (allocbufb==NULL) { /* hopeless -- abandon */
- *status|=DEC_Insufficient_storage;
- break;}
- b=allocbufb; /* use the allocated space */
- }
-
- /* Prepare an initial estimate in acc. Calculate this by */
- /* considering the coefficient of x to be a normalized fraction, */
- /* f, with the decimal point at far left and multiplied by */
- /* 10**r. Then, rhs=f*10**r and 0.1<=f<1, and */
- /* ln(x) = ln(f) + ln(10)*r */
- /* Get the initial estimate for ln(f) from a small lookup */
- /* table (see above) indexed by the first two digits of f, */
- /* truncated. */
-
- uprv_decContextDefault(&aset, DEC_INIT_DECIMAL64); /* 16-digit extended */
- r=rhs->exponent+rhs->digits; /* 'normalised' exponent */
- uprv_decNumberFromInt32(a, r); /* a=r */
- uprv_decNumberFromInt32(b, 2302585); /* b=ln(10) (2.302585) */
- b->exponent=-6; /* .. */
- decMultiplyOp(a, a, b, &aset, &ignore); /* a=a*b */
- /* now get top two digits of rhs into b by simple truncate and */
- /* force to integer */
- residue=0; /* (no residue) */
- aset.digits=2; aset.round=DEC_ROUND_DOWN;
- decCopyFit(b, rhs, &aset, &residue, &ignore); /* copy & shorten */
- b->exponent=0; /* make integer */
- t=decGetInt(b); /* [cannot fail] */
- if (t<10) t=X10(t); /* adjust single-digit b */
- t=LNnn[t-10]; /* look up ln(b) */
- uprv_decNumberFromInt32(b, t>>2); /* b=ln(b) coefficient */
- b->exponent=-(t&3)-3; /* set exponent */
- b->bits=DECNEG; /* ln(0.10)->ln(0.99) always -ve */
- aset.digits=16; aset.round=DEC_ROUND_HALF_EVEN; /* restore */
- decAddOp(a, a, b, &aset, 0, &ignore); /* acc=a+b */
- /* the initial estimate is now in a, with up to 4 digits correct. */
- /* When rhs is at or near Nmax the estimate will be low, so we */
- /* will approach it from below, avoiding overflow when calling exp. */
-
- uprv_decNumberZero(&numone); *numone.lsu=1; /* constant 1 for adjustment */
-
- /* accumulator bounds are as requested (could underflow, but */
- /* cannot overflow) */
- aset.emax=set->emax;
- aset.emin=set->emin;
- aset.clamp=0; /* no concrete format */
- /* set up a context to be used for the multiply and subtract */
- bset=aset;
- bset.emax=DEC_MAX_MATH*2; /* use double bounds for the */
- bset.emin=-DEC_MAX_MATH*2; /* adjustment calculation */
- /* [see decExpOp call below] */
- /* for each iteration double the number of digits to calculate, */
- /* up to a maximum of p */
- pp=9; /* initial precision */
- /* [initially 9 as then the sequence starts 7+2, 16+2, and */
- /* 34+2, which is ideal for standard-sized numbers] */
- aset.digits=pp; /* working context */
- bset.digits=pp+rhs->digits; /* wider context */
- for (;;) { /* iterate */
- #if DECCHECK
- iterations++;
- if (iterations>24) break; /* consider 9 * 2**24 */
- #endif
- /* calculate the adjustment (exp(-a)*x-1) into b. This is a */
- /* catastrophic subtraction but it really is the difference */
- /* from 1 that is of interest. */
- /* Use the internal entry point to Exp as it allows the double */
- /* range for calculating exp(-a) when a is the tiniest subnormal. */
- a->bits^=DECNEG; /* make -a */
- decExpOp(b, a, &bset, &ignore); /* b=exp(-a) */
- a->bits^=DECNEG; /* restore sign of a */
- /* now multiply by rhs and subtract 1, at the wider precision */
- decMultiplyOp(b, b, rhs, &bset, &ignore); /* b=b*rhs */
- decAddOp(b, b, &numone, &bset, DECNEG, &ignore); /* b=b-1 */
-
- /* the iteration ends when the adjustment cannot affect the */
- /* result by >=0.5 ulp (at the requested digits), which */
- /* is when its value is smaller than the accumulator by */
- /* set->digits+1 digits (or it is zero) -- this is a looser */
- /* requirement than for Exp because all that happens to the */
- /* accumulator after this is the final rounding (but note that */
- /* there must also be full precision in a, or a=0). */
-
- if (decNumberIsZero(b) ||
- (a->digits+a->exponent)>=(b->digits+b->exponent+set->digits+1)) {
- if (a->digits==p) break;
- if (decNumberIsZero(a)) {
- decCompareOp(&cmp, rhs, &numone, &aset, COMPARE, &ignore); /* rhs=1 ? */
- if (cmp.lsu[0]==0) a->exponent=0; /* yes, exact 0 */
- else *status|=(DEC_Inexact | DEC_Rounded); /* no, inexact */
- break;
- }
- /* force padding if adjustment has gone to 0 before full length */
- if (decNumberIsZero(b)) b->exponent=a->exponent-p;
- }
-
- /* not done yet ... */
- decAddOp(a, a, b, &aset, 0, &ignore); /* a=a+b for next estimate */
- if (pp==p) continue; /* precision is at maximum */
- /* lengthen the next calculation */
- pp=pp*2; /* double precision */
- if (pp>p) pp=p; /* clamp to maximum */
- aset.digits=pp; /* working context */
- bset.digits=pp+rhs->digits; /* wider context */
- } /* Newton's iteration */
-
- #if DECCHECK
- /* just a sanity check; remove the test to show always */
- if (iterations>24)
- printf("Ln iterations=%ld, status=%08lx, p=%ld, d=%ld\n",
- (LI)iterations, (LI)*status, (LI)p, (LI)rhs->digits);
- #endif
-
- /* Copy and round the result to res */
- residue=1; /* indicate dirt to right */
- if (ISZERO(a)) residue=0; /* .. unless underflowed to 0 */
- aset.digits=set->digits; /* [use default rounding] */
- decCopyFit(res, a, &aset, &residue, status); /* copy & shorten */
- decFinish(res, set, &residue, status); /* cleanup/set flags */
- } while(0); /* end protected */
-
- if (allocbufa!=NULL) free(allocbufa); /* drop any storage used */
- if (allocbufb!=NULL) free(allocbufb); /* .. */
- /* [status is handled by caller] */
- return res;
- } /* decLnOp */
-#if defined(__clang__) || U_GCC_MAJOR_MINOR >= 406
-#pragma GCC diagnostic pop
-#endif
-
-/* ------------------------------------------------------------------ */
-/* decQuantizeOp -- force exponent to requested value */
-/* */
-/* This computes C = op(A, B), where op adjusts the coefficient */
-/* of C (by rounding or shifting) such that the exponent (-scale) */
-/* of C has the value B or matches the exponent of B. */
-/* The numerical value of C will equal A, except for the effects of */
-/* any rounding that occurred. */
-/* */
-/* res is C, the result. C may be A or B */
-/* lhs is A, the number to adjust */
-/* rhs is B, the requested exponent */
-/* set is the context */
-/* quant is 1 for quantize or 0 for rescale */
-/* status is the status accumulator (this can be called without */
-/* risk of control loss) */
-/* */
-/* C must have space for set->digits digits. */
-/* */
-/* Unless there is an error or the result is infinite, the exponent */
-/* after the operation is guaranteed to be that requested. */
-/* ------------------------------------------------------------------ */
-static decNumber * decQuantizeOp(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set,
- Flag quant, uInt *status) {
- #if DECSUBSET
- decNumber *alloclhs=NULL; /* non-NULL if rounded lhs allocated */
- decNumber *allocrhs=NULL; /* .., rhs */
- #endif
- const decNumber *inrhs=rhs; /* save original rhs */
- Int reqdigits=set->digits; /* requested DIGITS */
- Int reqexp; /* requested exponent [-scale] */
- Int residue=0; /* rounding residue */
- Int etiny=set->emin-(reqdigits-1);
-
- #if DECCHECK
- if (decCheckOperands(res, lhs, rhs, set)) return res;
- #endif
-
- do { /* protect allocated storage */
- #if DECSUBSET
- if (!set->extended) {
- /* reduce operands and set lostDigits status, as needed */
- if (lhs->digits>reqdigits) {
- alloclhs=decRoundOperand(lhs, set, status);
- if (alloclhs==NULL) break;
- lhs=alloclhs;
- }
- if (rhs->digits>reqdigits) { /* [this only checks lostDigits] */
- allocrhs=decRoundOperand(rhs, set, status);
- if (allocrhs==NULL) break;
- rhs=allocrhs;
- }
- }
- #endif
- /* [following code does not require input rounding] */
-
- /* Handle special values */
- if (SPECIALARGS) {
- /* NaNs get usual processing */
- if (SPECIALARGS & (DECSNAN | DECNAN))
- decNaNs(res, lhs, rhs, set, status);
- /* one infinity but not both is bad */
- else if ((lhs->bits ^ rhs->bits) & DECINF)
- *status|=DEC_Invalid_operation;
- /* both infinity: return lhs */
- else uprv_decNumberCopy(res, lhs); /* [nop if in place] */
- break;
- }
-
- /* set requested exponent */
- if (quant) reqexp=inrhs->exponent; /* quantize -- match exponents */
- else { /* rescale -- use value of rhs */
- /* Original rhs must be an integer that fits and is in range, */
- /* which could be from -1999999997 to +999999999, thanks to */
- /* subnormals */
- reqexp=decGetInt(inrhs); /* [cannot fail] */
- }
-
- #if DECSUBSET
- if (!set->extended) etiny=set->emin; /* no subnormals */
- #endif
-
- if (reqexp==BADINT /* bad (rescale only) or .. */
- || reqexp==BIGODD || reqexp==BIGEVEN /* very big (ditto) or .. */
- || (reqexp<etiny) /* < lowest */
- || (reqexp>set->emax)) { /* > emax */
- *status|=DEC_Invalid_operation;
- break;}
-
- /* the RHS has been processed, so it can be overwritten now if necessary */
- if (ISZERO(lhs)) { /* zero coefficient unchanged */
- uprv_decNumberCopy(res, lhs); /* [nop if in place] */
- res->exponent=reqexp; /* .. just set exponent */
- #if DECSUBSET
- if (!set->extended) res->bits=0; /* subset specification; no -0 */
- #endif
- }
- else { /* non-zero lhs */
- Int adjust=reqexp-lhs->exponent; /* digit adjustment needed */
- /* if adjusted coefficient will definitely not fit, give up now */
- if ((lhs->digits-adjust)>reqdigits) {
- *status|=DEC_Invalid_operation;
- break;
- }
-
- if (adjust>0) { /* increasing exponent */
- /* this will decrease the length of the coefficient by adjust */
- /* digits, and must round as it does so */
- decContext workset; /* work */
- workset=*set; /* clone rounding, etc. */
- workset.digits=lhs->digits-adjust; /* set requested length */
- /* [note that the latter can be <1, here] */
- decCopyFit(res, lhs, &workset, &residue, status); /* fit to result */
- decApplyRound(res, &workset, residue, status); /* .. and round */
- residue=0; /* [used] */
- /* If just rounded a 999s case, exponent will be off by one; */
- /* adjust back (after checking space), if so. */
- if (res->exponent>reqexp) {
- /* re-check needed, e.g., for quantize(0.9999, 0.001) under */
- /* set->digits==3 */
- if (res->digits==reqdigits) { /* cannot shift by 1 */
- *status&=~(DEC_Inexact | DEC_Rounded); /* [clean these] */
- *status|=DEC_Invalid_operation;
- break;
- }
- res->digits=decShiftToMost(res->lsu, res->digits, 1); /* shift */
- res->exponent--; /* (re)adjust the exponent. */
- }
- #if DECSUBSET
- if (ISZERO(res) && !set->extended) res->bits=0; /* subset; no -0 */
- #endif
- } /* increase */
- else /* adjust<=0 */ { /* decreasing or = exponent */
- /* this will increase the length of the coefficient by -adjust */
- /* digits, by adding zero or more trailing zeros; this is */
- /* already checked for fit, above */
- uprv_decNumberCopy(res, lhs); /* [it will fit] */
- /* if padding needed (adjust<0), add it now... */
- if (adjust<0) {
- res->digits=decShiftToMost(res->lsu, res->digits, -adjust);
- res->exponent+=adjust; /* adjust the exponent */
- }
- } /* decrease */
- } /* non-zero */
-
- /* Check for overflow [do not use Finalize in this case, as an */
- /* overflow here is a "don't fit" situation] */
- if (res->exponent>set->emax-res->digits+1) { /* too big */
- *status|=DEC_Invalid_operation;
- break;
- }
- else {
- decFinalize(res, set, &residue, status); /* set subnormal flags */
- *status&=~DEC_Underflow; /* suppress Underflow [as per 754] */
- }
- } while(0); /* end protected */
-
- #if DECSUBSET
- if (allocrhs!=NULL) free(allocrhs); /* drop any storage used */
- if (alloclhs!=NULL) free(alloclhs); /* .. */
- #endif
- return res;
- } /* decQuantizeOp */
-
-/* ------------------------------------------------------------------ */
-/* decCompareOp -- compare, min, or max two Numbers */
-/* */
-/* This computes C = A ? B and carries out one of four operations: */
-/* COMPARE -- returns the signum (as a number) giving the */
-/* result of a comparison unless one or both */
-/* operands is a NaN (in which case a NaN results) */
-/* COMPSIG -- as COMPARE except that a quiet NaN raises */
-/* Invalid operation. */
-/* COMPMAX -- returns the larger of the operands, using the */
-/* 754 maxnum operation */
-/* COMPMAXMAG -- ditto, comparing absolute values */
-/* COMPMIN -- the 754 minnum operation */
-/* COMPMINMAG -- ditto, comparing absolute values */
-/* COMTOTAL -- returns the signum (as a number) giving the */
-/* result of a comparison using 754 total ordering */
-/* */
-/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
-/* lhs is A */
-/* rhs is B */
-/* set is the context */
-/* op is the operation flag */
-/* status is the usual accumulator */
-/* */
-/* C must have space for one digit for COMPARE or set->digits for */
-/* COMPMAX, COMPMIN, COMPMAXMAG, or COMPMINMAG. */
-/* ------------------------------------------------------------------ */
-/* The emphasis here is on speed for common cases, and avoiding */
-/* coefficient comparison if possible. */
-/* ------------------------------------------------------------------ */
-static decNumber * decCompareOp(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set,
- Flag op, uInt *status) {
- #if DECSUBSET
- decNumber *alloclhs=NULL; /* non-NULL if rounded lhs allocated */
- decNumber *allocrhs=NULL; /* .., rhs */
- #endif
- Int result=0; /* default result value */
- uByte merged; /* work */
-
- #if DECCHECK
- if (decCheckOperands(res, lhs, rhs, set)) return res;
- #endif
-
- do { /* protect allocated storage */
- #if DECSUBSET
- if (!set->extended) {
- /* reduce operands and set lostDigits status, as needed */
- if (lhs->digits>set->digits) {
- alloclhs=decRoundOperand(lhs, set, status);
- if (alloclhs==NULL) {result=BADINT; break;}
- lhs=alloclhs;
- }
- if (rhs->digits>set->digits) {
- allocrhs=decRoundOperand(rhs, set, status);
- if (allocrhs==NULL) {result=BADINT; break;}
- rhs=allocrhs;
- }
- }
- #endif
- /* [following code does not require input rounding] */
-
- /* If total ordering then handle differing signs 'up front' */
- if (op==COMPTOTAL) { /* total ordering */
- if (decNumberIsNegative(lhs) && !decNumberIsNegative(rhs)) {
- result=-1;
- break;
- }
- if (!decNumberIsNegative(lhs) && decNumberIsNegative(rhs)) {
- result=+1;
- break;
- }
- }
-
- /* handle NaNs specially; let infinities drop through */
- /* This assumes sNaN (even just one) leads to NaN. */
- merged=(lhs->bits | rhs->bits) & (DECSNAN | DECNAN);
- if (merged) { /* a NaN bit set */
- if (op==COMPARE); /* result will be NaN */
- else if (op==COMPSIG) /* treat qNaN as sNaN */
- *status|=DEC_Invalid_operation | DEC_sNaN;
- else if (op==COMPTOTAL) { /* total ordering, always finite */
- /* signs are known to be the same; compute the ordering here */
- /* as if the signs are both positive, then invert for negatives */
- if (!decNumberIsNaN(lhs)) result=-1;
- else if (!decNumberIsNaN(rhs)) result=+1;
- /* here if both NaNs */
- else if (decNumberIsSNaN(lhs) && decNumberIsQNaN(rhs)) result=-1;
- else if (decNumberIsQNaN(lhs) && decNumberIsSNaN(rhs)) result=+1;
- else { /* both NaN or both sNaN */
- /* now it just depends on the payload */
- result=decUnitCompare(lhs->lsu, D2U(lhs->digits),
- rhs->lsu, D2U(rhs->digits), 0);
- /* [Error not possible, as these are 'aligned'] */
- } /* both same NaNs */
- if (decNumberIsNegative(lhs)) result=-result;
- break;
- } /* total order */
-
- else if (merged & DECSNAN); /* sNaN -> qNaN */
- else { /* here if MIN or MAX and one or two quiet NaNs */
- /* min or max -- 754 rules ignore single NaN */
- if (!decNumberIsNaN(lhs) || !decNumberIsNaN(rhs)) {
- /* just one NaN; force choice to be the non-NaN operand */
- op=COMPMAX;
- if (lhs->bits & DECNAN) result=-1; /* pick rhs */
- else result=+1; /* pick lhs */
- break;
- }
- } /* max or min */
- op=COMPNAN; /* use special path */
- decNaNs(res, lhs, rhs, set, status); /* propagate NaN */
- break;
- }
- /* have numbers */
- if (op==COMPMAXMAG || op==COMPMINMAG) result=decCompare(lhs, rhs, 1);
- else result=decCompare(lhs, rhs, 0); /* sign matters */
- } while(0); /* end protected */
-
- if (result==BADINT) *status|=DEC_Insufficient_storage; /* rare */
- else {
- if (op==COMPARE || op==COMPSIG ||op==COMPTOTAL) { /* returning signum */
- if (op==COMPTOTAL && result==0) {
- /* operands are numerically equal or same NaN (and same sign, */
- /* tested first); if identical, leave result 0 */
- if (lhs->exponent!=rhs->exponent) {
- if (lhs->exponent<rhs->exponent) result=-1;
- else result=+1;
- if (decNumberIsNegative(lhs)) result=-result;
- } /* lexp!=rexp */
- } /* total-order by exponent */
- uprv_decNumberZero(res); /* [always a valid result] */
- if (result!=0) { /* must be -1 or +1 */
- *res->lsu=1;
- if (result<0) res->bits=DECNEG;
- }
- }
- else if (op==COMPNAN); /* special, drop through */
- else { /* MAX or MIN, non-NaN result */
- Int residue=0; /* rounding accumulator */
- /* choose the operand for the result */
- const decNumber *choice;
- if (result==0) { /* operands are numerically equal */
- /* choose according to sign then exponent (see 754) */
- uByte slhs=(lhs->bits & DECNEG);
- uByte srhs=(rhs->bits & DECNEG);
- #if DECSUBSET
- if (!set->extended) { /* subset: force left-hand */
- op=COMPMAX;
- result=+1;
- }
- else
- #endif
- if (slhs!=srhs) { /* signs differ */
- if (slhs) result=-1; /* rhs is max */
- else result=+1; /* lhs is max */
- }
- else if (slhs && srhs) { /* both negative */
- if (lhs->exponent<rhs->exponent) result=+1;
- else result=-1;
- /* [if equal, use lhs, technically identical] */
- }
- else { /* both positive */
- if (lhs->exponent>rhs->exponent) result=+1;
- else result=-1;
- /* [ditto] */
- }
- } /* numerically equal */
- /* here result will be non-0; reverse if looking for MIN */
- if (op==COMPMIN || op==COMPMINMAG) result=-result;
- choice=(result>0 ? lhs : rhs); /* choose */
- /* copy chosen to result, rounding if need be */
- decCopyFit(res, choice, set, &residue, status);
- decFinish(res, set, &residue, status);
- }
- }
- #if DECSUBSET
- if (allocrhs!=NULL) free(allocrhs); /* free any storage used */
- if (alloclhs!=NULL) free(alloclhs); /* .. */
- #endif
- return res;
- } /* decCompareOp */
-
-/* ------------------------------------------------------------------ */
-/* decCompare -- compare two decNumbers by numerical value */
-/* */
-/* This routine compares A ? B without altering them. */
-/* */
-/* Arg1 is A, a decNumber which is not a NaN */
-/* Arg2 is B, a decNumber which is not a NaN */
-/* Arg3 is 1 for a sign-independent compare, 0 otherwise */
-/* */
-/* returns -1, 0, or 1 for A<B, A==B, or A>B, or BADINT if failure */
-/* (the only possible failure is an allocation error) */
-/* ------------------------------------------------------------------ */
-static Int decCompare(const decNumber *lhs, const decNumber *rhs,
- Flag abs_c) {
- Int result; /* result value */
- Int sigr; /* rhs signum */
- Int compare; /* work */
-
- result=1; /* assume signum(lhs) */
- if (ISZERO(lhs)) result=0;
- if (abs_c) {
- if (ISZERO(rhs)) return result; /* LHS wins or both 0 */
- /* RHS is non-zero */
- if (result==0) return -1; /* LHS is 0; RHS wins */
- /* [here, both non-zero, result=1] */
- }
- else { /* signs matter */
- if (result && decNumberIsNegative(lhs)) result=-1;
- sigr=1; /* compute signum(rhs) */
- if (ISZERO(rhs)) sigr=0;
- else if (decNumberIsNegative(rhs)) sigr=-1;
- if (result > sigr) return +1; /* L > R, return 1 */
- if (result < sigr) return -1; /* L < R, return -1 */
- if (result==0) return 0; /* both 0 */
- }
-
- /* signums are the same; both are non-zero */
- if ((lhs->bits | rhs->bits) & DECINF) { /* one or more infinities */
- if (decNumberIsInfinite(rhs)) {
- if (decNumberIsInfinite(lhs)) result=0;/* both infinite */
- else result=-result; /* only rhs infinite */
- }
- return result;
- }
- /* must compare the coefficients, allowing for exponents */
- if (lhs->exponent>rhs->exponent) { /* LHS exponent larger */
- /* swap sides, and sign */
- const decNumber *temp=lhs;
- lhs=rhs;
- rhs=temp;
- result=-result;
- }
- compare=decUnitCompare(lhs->lsu, D2U(lhs->digits),
- rhs->lsu, D2U(rhs->digits),
- rhs->exponent-lhs->exponent);
- if (compare!=BADINT) compare*=result; /* comparison succeeded */
- return compare;
- } /* decCompare */
-
-/* ------------------------------------------------------------------ */
-/* decUnitCompare -- compare two >=0 integers in Unit arrays */
-/* */
-/* This routine compares A ? B*10**E where A and B are unit arrays */
-/* A is a plain integer */
-/* B has an exponent of E (which must be non-negative) */
-/* */
-/* Arg1 is A first Unit (lsu) */
-/* Arg2 is A length in Units */
-/* Arg3 is B first Unit (lsu) */
-/* Arg4 is B length in Units */
-/* Arg5 is E (0 if the units are aligned) */
-/* */
-/* returns -1, 0, or 1 for A<B, A==B, or A>B, or BADINT if failure */
-/* (the only possible failure is an allocation error, which can */
-/* only occur if E!=0) */
-/* ------------------------------------------------------------------ */
-static Int decUnitCompare(const Unit *a, Int alength,
- const Unit *b, Int blength, Int exp) {
- Unit *acc; /* accumulator for result */
- Unit accbuff[SD2U(DECBUFFER*2+1)]; /* local buffer */
- Unit *allocacc=NULL; /* -> allocated acc buffer, iff allocated */
- Int accunits, need; /* units in use or needed for acc */
- const Unit *l, *r, *u; /* work */
- Int expunits, exprem, result; /* .. */
-
- if (exp==0) { /* aligned; fastpath */
- if (alength>blength) return 1;
- if (alength<blength) return -1;
- /* same number of units in both -- need unit-by-unit compare */
- l=a+alength-1;
- r=b+alength-1;
- for (;l>=a; l--, r--) {
- if (*l>*r) return 1;
- if (*l<*r) return -1;
- }
- return 0; /* all units match */
- } /* aligned */
-
- /* Unaligned. If one is >1 unit longer than the other, padded */
- /* approximately, then can return easily */
- if (alength>blength+(Int)D2U(exp)) return 1;
- if (alength+1<blength+(Int)D2U(exp)) return -1;
-
- /* Need to do a real subtract. For this, a result buffer is needed */
- /* even though only the sign is of interest. Its length needs */
- /* to be the larger of alength and padded blength, +2 */
- need=blength+D2U(exp); /* maximum real length of B */
- if (need<alength) need=alength;
- need+=2;
- acc=accbuff; /* assume use local buffer */
- if (need*sizeof(Unit)>sizeof(accbuff)) {
- allocacc=(Unit *)malloc(need*sizeof(Unit));
- if (allocacc==NULL) return BADINT; /* hopeless -- abandon */
- acc=allocacc;
- }
- /* Calculate units and remainder from exponent. */
- expunits=exp/DECDPUN;
- exprem=exp%DECDPUN;
- /* subtract [A+B*(-m)] */
- accunits=decUnitAddSub(a, alength, b, blength, expunits, acc,
- -(Int)powers[exprem]);
- /* [UnitAddSub result may have leading zeros, even on zero] */
- if (accunits<0) result=-1; /* negative result */
- else { /* non-negative result */
- /* check units of the result before freeing any storage */
- for (u=acc; u<acc+accunits-1 && *u==0;) u++;
- result=(*u==0 ? 0 : +1);
- }
- /* clean up and return the result */
- if (allocacc!=NULL) free(allocacc); /* drop any storage used */
- return result;
- } /* decUnitCompare */
-
-/* ------------------------------------------------------------------ */
-/* decUnitAddSub -- add or subtract two >=0 integers in Unit arrays */
-/* */
-/* This routine performs the calculation: */
-/* */
-/* C=A+(B*M) */
-/* */
-/* Where M is in the range -DECDPUNMAX through +DECDPUNMAX. */
-/* */
-/* A may be shorter or longer than B. */
-/* */
-/* Leading zeros are not removed after a calculation. The result is */
-/* either the same length as the longer of A and B (adding any */
-/* shift), or one Unit longer than that (if a Unit carry occurred). */
-/* */
-/* A and B content are not altered unless C is also A or B. */
-/* C may be the same array as A or B, but only if no zero padding is */
-/* requested (that is, C may be B only if bshift==0). */
-/* C is filled from the lsu; only those units necessary to complete */
-/* the calculation are referenced. */
-/* */
-/* Arg1 is A first Unit (lsu) */
-/* Arg2 is A length in Units */
-/* Arg3 is B first Unit (lsu) */
-/* Arg4 is B length in Units */
-/* Arg5 is B shift in Units (>=0; pads with 0 units if positive) */
-/* Arg6 is C first Unit (lsu) */
-/* Arg7 is M, the multiplier */
-/* */
-/* returns the count of Units written to C, which will be non-zero */
-/* and negated if the result is negative. That is, the sign of the */
-/* returned Int is the sign of the result (positive for zero) and */
-/* the absolute value of the Int is the count of Units. */
-/* */
-/* It is the caller's responsibility to make sure that C size is */
-/* safe, allowing space if necessary for a one-Unit carry. */
-/* */
-/* This routine is severely performance-critical; *any* change here */
-/* must be measured (timed) to assure no performance degradation. */
-/* In particular, trickery here tends to be counter-productive, as */
-/* increased complexity of code hurts register optimizations on */
-/* register-poor architectures. Avoiding divisions is nearly */
-/* always a Good Idea, however. */
-/* */
-/* Special thanks to Rick McGuire (IBM Cambridge, MA) and Dave Clark */
-/* (IBM Warwick, UK) for some of the ideas used in this routine. */
-/* ------------------------------------------------------------------ */
-static Int decUnitAddSub(const Unit *a, Int alength,
- const Unit *b, Int blength, Int bshift,
- Unit *c, Int m) {
- const Unit *alsu=a; /* A lsu [need to remember it] */
- Unit *clsu=c; /* C ditto */
- Unit *minC; /* low water mark for C */
- Unit *maxC; /* high water mark for C */
- eInt carry=0; /* carry integer (could be Long) */
- Int add; /* work */
- #if DECDPUN<=4 /* myriadal, millenary, etc. */
- Int est; /* estimated quotient */
- #endif
-
- #if DECTRACE
- if (alength<1 || blength<1)
- printf("decUnitAddSub: alen blen m %ld %ld [%ld]\n", alength, blength, m);
- #endif
-
- maxC=c+alength; /* A is usually the longer */
- minC=c+blength; /* .. and B the shorter */
- if (bshift!=0) { /* B is shifted; low As copy across */
- minC+=bshift;
- /* if in place [common], skip copy unless there's a gap [rare] */
- if (a==c && bshift<=alength) {
- c+=bshift;
- a+=bshift;
- }
- else for (; c<clsu+bshift; a++, c++) { /* copy needed */
- if (a<alsu+alength) *c=*a;
- else *c=0;
- }
- }
- if (minC>maxC) { /* swap */
- Unit *hold=minC;
- minC=maxC;
- maxC=hold;
- }
-
- /* For speed, do the addition as two loops; the first where both A */
- /* and B contribute, and the second (if necessary) where only one or */
- /* other of the numbers contribute. */
- /* Carry handling is the same (i.e., duplicated) in each case. */
- for (; c<minC; c++) {
- carry+=*a;
- a++;
- carry+=((eInt)*b)*m; /* [special-casing m=1/-1 */
- b++; /* here is not a win] */
- /* here carry is new Unit of digits; it could be +ve or -ve */
- if ((ueInt)carry<=DECDPUNMAX) { /* fastpath 0-DECDPUNMAX */
- *c=(Unit)carry;
- carry=0;
- continue;
- }
- #if DECDPUN==4 /* use divide-by-multiply */
- if (carry>=0) {
- est=(((ueInt)carry>>11)*53687)>>18;
- *c=(Unit)(carry-est*(DECDPUNMAX+1)); /* remainder */
- carry=est; /* likely quotient [89%] */
- if (*c<DECDPUNMAX+1) continue; /* estimate was correct */
- carry++;
- *c-=DECDPUNMAX+1;
- continue;
- }
- /* negative case */
- carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
- est=(((ueInt)carry>>11)*53687)>>18;
- *c=(Unit)(carry-est*(DECDPUNMAX+1));
- carry=est-(DECDPUNMAX+1); /* correctly negative */
- if (*c<DECDPUNMAX+1) continue; /* was OK */
- carry++;
- *c-=DECDPUNMAX+1;
- #elif DECDPUN==3
- if (carry>=0) {
- est=(((ueInt)carry>>3)*16777)>>21;
- *c=(Unit)(carry-est*(DECDPUNMAX+1)); /* remainder */
- carry=est; /* likely quotient [99%] */
- if (*c<DECDPUNMAX+1) continue; /* estimate was correct */
- carry++;
- *c-=DECDPUNMAX+1;
- continue;
- }
- /* negative case */
- carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
- est=(((ueInt)carry>>3)*16777)>>21;
- *c=(Unit)(carry-est*(DECDPUNMAX+1));
- carry=est-(DECDPUNMAX+1); /* correctly negative */
- if (*c<DECDPUNMAX+1) continue; /* was OK */
- carry++;
- *c-=DECDPUNMAX+1;
- #elif DECDPUN<=2
- /* Can use QUOT10 as carry <= 4 digits */
- if (carry>=0) {
- est=QUOT10(carry, DECDPUN);
- *c=(Unit)(carry-est*(DECDPUNMAX+1)); /* remainder */
- carry=est; /* quotient */
- continue;
- }
- /* negative case */
- carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
- est=QUOT10(carry, DECDPUN);
- *c=(Unit)(carry-est*(DECDPUNMAX+1));
- carry=est-(DECDPUNMAX+1); /* correctly negative */
- #else
- /* remainder operator is undefined if negative, so must test */
- if ((ueInt)carry<(DECDPUNMAX+1)*2) { /* fastpath carry +1 */
- *c=(Unit)(carry-(DECDPUNMAX+1)); /* [helps additions] */
- carry=1;
- continue;
- }
- if (carry>=0) {
- *c=(Unit)(carry%(DECDPUNMAX+1));
- carry=carry/(DECDPUNMAX+1);
- continue;
- }
- /* negative case */
- carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
- *c=(Unit)(carry%(DECDPUNMAX+1));
- carry=carry/(DECDPUNMAX+1)-(DECDPUNMAX+1);
- #endif
- } /* c */
-
- /* now may have one or other to complete */
- /* [pretest to avoid loop setup/shutdown] */
- if (c<maxC) for (; c<maxC; c++) {
- if (a<alsu+alength) { /* still in A */
- carry+=*a;
- a++;
- }
- else { /* inside B */
- carry+=((eInt)*b)*m;
- b++;
- }
- /* here carry is new Unit of digits; it could be +ve or -ve and */
- /* magnitude up to DECDPUNMAX squared */
- if ((ueInt)carry<=DECDPUNMAX) { /* fastpath 0-DECDPUNMAX */
- *c=(Unit)carry;
- carry=0;
- continue;
- }
- /* result for this unit is negative or >DECDPUNMAX */
- #if DECDPUN==4 /* use divide-by-multiply */
- if (carry>=0) {
- est=(((ueInt)carry>>11)*53687)>>18;
- *c=(Unit)(carry-est*(DECDPUNMAX+1)); /* remainder */
- carry=est; /* likely quotient [79.7%] */
- if (*c<DECDPUNMAX+1) continue; /* estimate was correct */
- carry++;
- *c-=DECDPUNMAX+1;
- continue;
- }
- /* negative case */
- carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
- est=(((ueInt)carry>>11)*53687)>>18;
- *c=(Unit)(carry-est*(DECDPUNMAX+1));
- carry=est-(DECDPUNMAX+1); /* correctly negative */
- if (*c<DECDPUNMAX+1) continue; /* was OK */
- carry++;
- *c-=DECDPUNMAX+1;
- #elif DECDPUN==3
- if (carry>=0) {
- est=(((ueInt)carry>>3)*16777)>>21;
- *c=(Unit)(carry-est*(DECDPUNMAX+1)); /* remainder */
- carry=est; /* likely quotient [99%] */
- if (*c<DECDPUNMAX+1) continue; /* estimate was correct */
- carry++;
- *c-=DECDPUNMAX+1;
- continue;
- }
- /* negative case */
- carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
- est=(((ueInt)carry>>3)*16777)>>21;
- *c=(Unit)(carry-est*(DECDPUNMAX+1));
- carry=est-(DECDPUNMAX+1); /* correctly negative */
- if (*c<DECDPUNMAX+1) continue; /* was OK */
- carry++;
- *c-=DECDPUNMAX+1;
- #elif DECDPUN<=2
- if (carry>=0) {
- est=QUOT10(carry, DECDPUN);
- *c=(Unit)(carry-est*(DECDPUNMAX+1)); /* remainder */
- carry=est; /* quotient */
- continue;
- }
- /* negative case */
- carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
- est=QUOT10(carry, DECDPUN);
- *c=(Unit)(carry-est*(DECDPUNMAX+1));
- carry=est-(DECDPUNMAX+1); /* correctly negative */
- #else
- if ((ueInt)carry<(DECDPUNMAX+1)*2){ /* fastpath carry 1 */
- *c=(Unit)(carry-(DECDPUNMAX+1));
- carry=1;
- continue;
- }
- /* remainder operator is undefined if negative, so must test */
- if (carry>=0) {
- *c=(Unit)(carry%(DECDPUNMAX+1));
- carry=carry/(DECDPUNMAX+1);
- continue;
- }
- /* negative case */
- carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
- *c=(Unit)(carry%(DECDPUNMAX+1));
- carry=carry/(DECDPUNMAX+1)-(DECDPUNMAX+1);
- #endif
- } /* c */
-
- /* OK, all A and B processed; might still have carry or borrow */
- /* return number of Units in the result, negated if a borrow */
- if (carry==0) return static_cast<int32_t>(c-clsu); /* no carry, so no more to do */
- if (carry>0) { /* positive carry */
- *c=(Unit)carry; /* place as new unit */
- c++; /* .. */
- return static_cast<int32_t>(c-clsu);
- }
- /* -ve carry: it's a borrow; complement needed */
- add=1; /* temporary carry... */
- for (c=clsu; c<maxC; c++) {
- add=DECDPUNMAX+add-*c;
- if (add<=DECDPUNMAX) {
- *c=(Unit)add;
- add=0;
- }
- else {
- *c=0;
- add=1;
- }
- }
- /* add an extra unit iff it would be non-zero */
- #if DECTRACE
- printf("UAS borrow: add %ld, carry %ld\n", add, carry);
- #endif
- if ((add-carry-1)!=0) {
- *c=(Unit)(add-carry-1);
- c++; /* interesting, include it */
- }
- return static_cast<int32_t>(clsu-c); /* -ve result indicates borrowed */
- } /* decUnitAddSub */
-
-/* ------------------------------------------------------------------ */
-/* decTrim -- trim trailing zeros or normalize */
-/* */
-/* dn is the number to trim or normalize */
-/* set is the context to use to check for clamp */
-/* all is 1 to remove all trailing zeros, 0 for just fraction ones */
-/* noclamp is 1 to unconditional (unclamped) trim */
-/* dropped returns the number of discarded trailing zeros */
-/* returns dn */
-/* */
-/* If clamp is set in the context then the number of zeros trimmed */
-/* may be limited if the exponent is high. */
-/* All fields are updated as required. This is a utility operation, */
-/* so special values are unchanged and no error is possible. */
-/* ------------------------------------------------------------------ */
-static decNumber * decTrim(decNumber *dn, decContext *set, Flag all,
- Flag noclamp, Int *dropped) {
- Int d, exp; /* work */
- uInt cut; /* .. */
- Unit *up; /* -> current Unit */
-
- #if DECCHECK
- if (decCheckOperands(dn, DECUNUSED, DECUNUSED, DECUNCONT)) return dn;
- #endif
-
- *dropped=0; /* assume no zeros dropped */
- if ((dn->bits & DECSPECIAL) /* fast exit if special .. */
- || (*dn->lsu & 0x01)) return dn; /* .. or odd */
- if (ISZERO(dn)) { /* .. or 0 */
- dn->exponent=0; /* (sign is preserved) */
- return dn;
- }
-
- /* have a finite number which is even */
- exp=dn->exponent;
- cut=1; /* digit (1-DECDPUN) in Unit */
- up=dn->lsu; /* -> current Unit */
- for (d=0; d<dn->digits-1; d++) { /* [don't strip the final digit] */
- /* slice by powers */
- #if DECDPUN<=4
- uInt quot=QUOT10(*up, cut);
- if ((*up-quot*powers[cut])!=0) break; /* found non-0 digit */
- #else
- if (*up%powers[cut]!=0) break; /* found non-0 digit */
- #endif
- /* have a trailing 0 */
- if (!all) { /* trimming */
- /* [if exp>0 then all trailing 0s are significant for trim] */
- if (exp<=0) { /* if digit might be significant */
- if (exp==0) break; /* then quit */
- exp++; /* next digit might be significant */
- }
- }
- cut++; /* next power */
- if (cut>DECDPUN) { /* need new Unit */
- up++;
- cut=1;
- }
- } /* d */
- if (d==0) return dn; /* none to drop */
-
- /* may need to limit drop if clamping */
- if (set->clamp && !noclamp) {
- Int maxd=set->emax-set->digits+1-dn->exponent;
- if (maxd<=0) return dn; /* nothing possible */
- if (d>maxd) d=maxd;
- }
-
- /* effect the drop */
- decShiftToLeast(dn->lsu, D2U(dn->digits), d);
- dn->exponent+=d; /* maintain numerical value */
- dn->digits-=d; /* new length */
- *dropped=d; /* report the count */
- return dn;
- } /* decTrim */
-
-/* ------------------------------------------------------------------ */
-/* decReverse -- reverse a Unit array in place */
-/* */
-/* ulo is the start of the array */
-/* uhi is the end of the array (highest Unit to include) */
-/* */
-/* The units ulo through uhi are reversed in place (if the number */
-/* of units is odd, the middle one is untouched). Note that the */
-/* digit(s) in each unit are unaffected. */
-/* ------------------------------------------------------------------ */
-static void decReverse(Unit *ulo, Unit *uhi) {
- Unit temp;
- for (; ulo<uhi; ulo++, uhi--) {
- temp=*ulo;
- *ulo=*uhi;
- *uhi=temp;
- }
- return;
- } /* decReverse */
-
-/* ------------------------------------------------------------------ */
-/* decShiftToMost -- shift digits in array towards most significant */
-/* */
-/* uar is the array */
-/* digits is the count of digits in use in the array */
-/* shift is the number of zeros to pad with (least significant); */
-/* it must be zero or positive */
-/* */
-/* returns the new length of the integer in the array, in digits */
-/* */
-/* No overflow is permitted (that is, the uar array must be known to */
-/* be large enough to hold the result, after shifting). */
-/* ------------------------------------------------------------------ */
-static Int decShiftToMost(Unit *uar, Int digits, Int shift) {
- Unit *target, *source, *first; /* work */
- Int cut; /* odd 0's to add */
- uInt next; /* work */
-
- if (shift==0) return digits; /* [fastpath] nothing to do */
- if ((digits+shift)<=DECDPUN) { /* [fastpath] single-unit case */
- *uar=(Unit)(*uar*powers[shift]);
- return digits+shift;
- }
-
- next=0; /* all paths */
- source=uar+D2U(digits)-1; /* where msu comes from */
- target=source+D2U(shift); /* where upper part of first cut goes */
- cut=DECDPUN-MSUDIGITS(shift); /* where to slice */
- if (cut==0) { /* unit-boundary case */
- for (; source>=uar; source--, target--) *target=*source;
- }
- else {
- first=uar+D2U(digits+shift)-1; /* where msu of source will end up */
- for (; source>=uar; source--, target--) {
- /* split the source Unit and accumulate remainder for next */
- #if DECDPUN<=4
- uInt quot=QUOT10(*source, cut);
- uInt rem=*source-quot*powers[cut];
- next+=quot;
- #else
- uInt rem=*source%powers[cut];
- next+=*source/powers[cut];
- #endif
- if (target<=first) *target=(Unit)next; /* write to target iff valid */
- next=rem*powers[DECDPUN-cut]; /* save remainder for next Unit */
- }
- } /* shift-move */
-
- /* propagate any partial unit to one below and clear the rest */
- for (; target>=uar; target--) {
- *target=(Unit)next;
- next=0;
- }
- return digits+shift;
- } /* decShiftToMost */
-
-/* ------------------------------------------------------------------ */
-/* decShiftToLeast -- shift digits in array towards least significant */
-/* */
-/* uar is the array */
-/* units is length of the array, in units */
-/* shift is the number of digits to remove from the lsu end; it */
-/* must be zero or positive and <= than units*DECDPUN. */
-/* */
-/* returns the new length of the integer in the array, in units */
-/* */
-/* Removed digits are discarded (lost). Units not required to hold */
-/* the final result are unchanged. */
-/* ------------------------------------------------------------------ */
-static Int decShiftToLeast(Unit *uar, Int units, Int shift) {
- Unit *target, *up; /* work */
- Int cut, count; /* work */
- Int quot, rem; /* for division */
-
- if (shift==0) return units; /* [fastpath] nothing to do */
- if (shift==units*DECDPUN) { /* [fastpath] little to do */
- *uar=0; /* all digits cleared gives zero */
- return 1; /* leaves just the one */
- }
-
- target=uar; /* both paths */
- cut=MSUDIGITS(shift);
- if (cut==DECDPUN) { /* unit-boundary case; easy */
- up=uar+D2U(shift);
- for (; up<uar+units; target++, up++) *target=*up;
- return static_cast<int32_t>(target-uar);
- }
-
- /* messier */
- up=uar+D2U(shift-cut); /* source; correct to whole Units */
- count=units*DECDPUN-shift; /* the maximum new length */
- #if DECDPUN<=4
- quot=QUOT10(*up, cut);
- #else
- quot=*up/powers[cut];
- #endif
- for (; ; target++) {
- *target=(Unit)quot;
- count-=(DECDPUN-cut);
- if (count<=0) break;
- up++;
- quot=*up;
- #if DECDPUN<=4
- quot=QUOT10(quot, cut);
- rem=*up-quot*powers[cut];
- #else
- rem=quot%powers[cut];
- quot=quot/powers[cut];
- #endif
- *target=(Unit)(*target+rem*powers[DECDPUN-cut]);
- count-=cut;
- if (count<=0) break;
- }
- return static_cast<int32_t>(target-uar+1);
- } /* decShiftToLeast */
-
-#if DECSUBSET
-/* ------------------------------------------------------------------ */
-/* decRoundOperand -- round an operand [used for subset only] */
-/* */
-/* dn is the number to round (dn->digits is > set->digits) */
-/* set is the relevant context */
-/* status is the status accumulator */
-/* */
-/* returns an allocated decNumber with the rounded result. */
-/* */
-/* lostDigits and other status may be set by this. */
-/* */
-/* Since the input is an operand, it must not be modified. */
-/* Instead, return an allocated decNumber, rounded as required. */
-/* It is the caller's responsibility to free the allocated storage. */
-/* */
-/* If no storage is available then the result cannot be used, so NULL */
-/* is returned. */
-/* ------------------------------------------------------------------ */
-static decNumber *decRoundOperand(const decNumber *dn, decContext *set,
- uInt *status) {
- decNumber *res; /* result structure */
- uInt newstatus=0; /* status from round */
- Int residue=0; /* rounding accumulator */
-
- /* Allocate storage for the returned decNumber, big enough for the */
- /* length specified by the context */
- res=(decNumber *)malloc(sizeof(decNumber)
- +(D2U(set->digits)-1)*sizeof(Unit));
- if (res==NULL) {
- *status|=DEC_Insufficient_storage;
- return NULL;
- }
- decCopyFit(res, dn, set, &residue, &newstatus);
- decApplyRound(res, set, residue, &newstatus);
-
- /* If that set Inexact then "lost digits" is raised... */
- if (newstatus & DEC_Inexact) newstatus|=DEC_Lost_digits;
- *status|=newstatus;
- return res;
- } /* decRoundOperand */
-#endif
-
-/* ------------------------------------------------------------------ */
-/* decCopyFit -- copy a number, truncating the coefficient if needed */
-/* */
-/* dest is the target decNumber */
-/* src is the source decNumber */
-/* set is the context [used for length (digits) and rounding mode] */
-/* residue is the residue accumulator */
-/* status contains the current status to be updated */
-/* */
-/* (dest==src is allowed and will be a no-op if fits) */
-/* All fields are updated as required. */
-/* ------------------------------------------------------------------ */
-static void decCopyFit(decNumber *dest, const decNumber *src,
- decContext *set, Int *residue, uInt *status) {
- dest->bits=src->bits;
- dest->exponent=src->exponent;
- decSetCoeff(dest, set, src->lsu, src->digits, residue, status);
- } /* decCopyFit */
-
-/* ------------------------------------------------------------------ */
-/* decSetCoeff -- set the coefficient of a number */
-/* */
-/* dn is the number whose coefficient array is to be set. */
-/* It must have space for set->digits digits */
-/* set is the context [for size] */
-/* lsu -> lsu of the source coefficient [may be dn->lsu] */
-/* len is digits in the source coefficient [may be dn->digits] */
-/* residue is the residue accumulator. This has values as in */
-/* decApplyRound, and will be unchanged unless the */
-/* target size is less than len. In this case, the */
-/* coefficient is truncated and the residue is updated to */
-/* reflect the previous residue and the dropped digits. */
-/* status is the status accumulator, as usual */
-/* */
-/* The coefficient may already be in the number, or it can be an */
-/* external intermediate array. If it is in the number, lsu must == */
-/* dn->lsu and len must == dn->digits. */
-/* */
-/* Note that the coefficient length (len) may be < set->digits, and */
-/* in this case this merely copies the coefficient (or is a no-op */
-/* if dn->lsu==lsu). */
-/* */
-/* Note also that (only internally, from decQuantizeOp and */
-/* decSetSubnormal) the value of set->digits may be less than one, */
-/* indicating a round to left. This routine handles that case */
-/* correctly; caller ensures space. */
-/* */
-/* dn->digits, dn->lsu (and as required), and dn->exponent are */
-/* updated as necessary. dn->bits (sign) is unchanged. */
-/* */
-/* DEC_Rounded status is set if any digits are discarded. */
-/* DEC_Inexact status is set if any non-zero digits are discarded, or */
-/* incoming residue was non-0 (implies rounded) */
-/* ------------------------------------------------------------------ */
-/* mapping array: maps 0-9 to canonical residues, so that a residue */
-/* can be adjusted in the range [-1, +1] and achieve correct rounding */
-/* 0 1 2 3 4 5 6 7 8 9 */
-static const uByte resmap[10]={0, 3, 3, 3, 3, 5, 7, 7, 7, 7};
-static void decSetCoeff(decNumber *dn, decContext *set, const Unit *lsu,
- Int len, Int *residue, uInt *status) {
- Int discard; /* number of digits to discard */
- uInt cut; /* cut point in Unit */
- const Unit *up; /* work */
- Unit *target; /* .. */
- Int count; /* .. */
- #if DECDPUN<=4
- uInt temp; /* .. */
- #endif
-
- discard=len-set->digits; /* digits to discard */
- if (discard<=0) { /* no digits are being discarded */
- if (dn->lsu!=lsu) { /* copy needed */
- /* copy the coefficient array to the result number; no shift needed */
- count=len; /* avoids D2U */
- up=lsu;
- for (target=dn->lsu; count>0; target++, up++, count-=DECDPUN)
- *target=*up;
- dn->digits=len; /* set the new length */
- }
- /* dn->exponent and residue are unchanged, record any inexactitude */
- if (*residue!=0) *status|=(DEC_Inexact | DEC_Rounded);
- return;
- }
-
- /* some digits must be discarded ... */
- dn->exponent+=discard; /* maintain numerical value */
- *status|=DEC_Rounded; /* accumulate Rounded status */
- if (*residue>1) *residue=1; /* previous residue now to right, so reduce */
-
- if (discard>len) { /* everything, +1, is being discarded */
- /* guard digit is 0 */
- /* residue is all the number [NB could be all 0s] */
- if (*residue<=0) { /* not already positive */
- count=len; /* avoids D2U */
- for (up=lsu; count>0; up++, count-=DECDPUN) if (*up!=0) { /* found non-0 */
- *residue=1;
- break; /* no need to check any others */
- }
- }
- if (*residue!=0) *status|=DEC_Inexact; /* record inexactitude */
- *dn->lsu=0; /* coefficient will now be 0 */
- dn->digits=1; /* .. */
- return;
- } /* total discard */
-
- /* partial discard [most common case] */
- /* here, at least the first (most significant) discarded digit exists */
-
- /* spin up the number, noting residue during the spin, until get to */
- /* the Unit with the first discarded digit. When reach it, extract */
- /* it and remember its position */
- count=0;
- for (up=lsu;; up++) {
- count+=DECDPUN;
- if (count>=discard) break; /* full ones all checked */
- if (*up!=0) *residue=1;
- } /* up */
-
- /* here up -> Unit with first discarded digit */
- cut=discard-(count-DECDPUN)-1;
- if (cut==DECDPUN-1) { /* unit-boundary case (fast) */
- Unit half=(Unit)powers[DECDPUN]>>1;
- /* set residue directly */
- if (*up>=half) {
- if (*up>half) *residue=7;
- else *residue+=5; /* add sticky bit */
- }
- else { /* <half */
- if (*up!=0) *residue=3; /* [else is 0, leave as sticky bit] */
- }
- if (set->digits<=0) { /* special for Quantize/Subnormal :-( */
- *dn->lsu=0; /* .. result is 0 */
- dn->digits=1; /* .. */
- }
- else { /* shift to least */
- count=set->digits; /* now digits to end up with */
- dn->digits=count; /* set the new length */
- up++; /* move to next */
- /* on unit boundary, so shift-down copy loop is simple */
- for (target=dn->lsu; count>0; target++, up++, count-=DECDPUN)
- *target=*up;
- }
- } /* unit-boundary case */
-
- else { /* discard digit is in low digit(s), and not top digit */
- uInt discard1; /* first discarded digit */
- uInt quot, rem; /* for divisions */
- if (cut==0) quot=*up; /* is at bottom of unit */
- else /* cut>0 */ { /* it's not at bottom of unit */
- #if DECDPUN<=4
- U_ASSERT(/* cut >= 0 &&*/ cut <= 4);
- quot=QUOT10(*up, cut);
- rem=*up-quot*powers[cut];
- #else
- rem=*up%powers[cut];
- quot=*up/powers[cut];
- #endif
- if (rem!=0) *residue=1;
- }
- /* discard digit is now at bottom of quot */
- #if DECDPUN<=4
- temp=(quot*6554)>>16; /* fast /10 */
- /* Vowels algorithm here not a win (9 instructions) */
- discard1=quot-X10(temp);
- quot=temp;
- #else
- discard1=quot%10;
- quot=quot/10;
- #endif
- /* here, discard1 is the guard digit, and residue is everything */
- /* else [use mapping array to accumulate residue safely] */
- *residue+=resmap[discard1];
- cut++; /* update cut */
- /* here: up -> Unit of the array with bottom digit */
- /* cut is the division point for each Unit */
- /* quot holds the uncut high-order digits for the current unit */
- if (set->digits<=0) { /* special for Quantize/Subnormal :-( */
- *dn->lsu=0; /* .. result is 0 */
- dn->digits=1; /* .. */
- }
- else { /* shift to least needed */
- count=set->digits; /* now digits to end up with */
- dn->digits=count; /* set the new length */
- /* shift-copy the coefficient array to the result number */
- for (target=dn->lsu; ; target++) {
- *target=(Unit)quot;
- count-=(DECDPUN-cut);
- if (count<=0) break;
- up++;
- quot=*up;
- #if DECDPUN<=4
- quot=QUOT10(quot, cut);
- rem=*up-quot*powers[cut];
- #else
- rem=quot%powers[cut];
- quot=quot/powers[cut];
- #endif
- *target=(Unit)(*target+rem*powers[DECDPUN-cut]);
- count-=cut;
- if (count<=0) break;
- } /* shift-copy loop */
- } /* shift to least */
- } /* not unit boundary */
-
- if (*residue!=0) *status|=DEC_Inexact; /* record inexactitude */
- return;
- } /* decSetCoeff */
-
-/* ------------------------------------------------------------------ */
-/* decApplyRound -- apply pending rounding to a number */
-/* */
-/* dn is the number, with space for set->digits digits */
-/* set is the context [for size and rounding mode] */
-/* residue indicates pending rounding, being any accumulated */
-/* guard and sticky information. It may be: */
-/* 6-9: rounding digit is >5 */
-/* 5: rounding digit is exactly half-way */
-/* 1-4: rounding digit is <5 and >0 */
-/* 0: the coefficient is exact */
-/* -1: as 1, but the hidden digits are subtractive, that */
-/* is, of the opposite sign to dn. In this case the */
-/* coefficient must be non-0. This case occurs when */
-/* subtracting a small number (which can be reduced to */
-/* a sticky bit); see decAddOp. */
-/* status is the status accumulator, as usual */
-/* */
-/* This routine applies rounding while keeping the length of the */
-/* coefficient constant. The exponent and status are unchanged */
-/* except if: */
-/* */
-/* -- the coefficient was increased and is all nines (in which */
-/* case Overflow could occur, and is handled directly here so */
-/* the caller does not need to re-test for overflow) */
-/* */
-/* -- the coefficient was decreased and becomes all nines (in which */
-/* case Underflow could occur, and is also handled directly). */
-/* */
-/* All fields in dn are updated as required. */
-/* */
-/* ------------------------------------------------------------------ */
-static void decApplyRound(decNumber *dn, decContext *set, Int residue,
- uInt *status) {
- Int bump; /* 1 if coefficient needs to be incremented */
- /* -1 if coefficient needs to be decremented */
-
- if (residue==0) return; /* nothing to apply */
-
- bump=0; /* assume a smooth ride */
-
- /* now decide whether, and how, to round, depending on mode */
- switch (set->round) {
- case DEC_ROUND_05UP: { /* round zero or five up (for reround) */
- /* This is the same as DEC_ROUND_DOWN unless there is a */
- /* positive residue and the lsd of dn is 0 or 5, in which case */
- /* it is bumped; when residue is <0, the number is therefore */
- /* bumped down unless the final digit was 1 or 6 (in which */
- /* case it is bumped down and then up -- a no-op) */
- Int lsd5=*dn->lsu%5; /* get lsd and quintate */
- if (residue<0 && lsd5!=1) bump=-1;
- else if (residue>0 && lsd5==0) bump=1;
- /* [bump==1 could be applied directly; use common path for clarity] */
- break;} /* r-05 */
-
- case DEC_ROUND_DOWN: {
- /* no change, except if negative residue */
- if (residue<0) bump=-1;
- break;} /* r-d */
-
- case DEC_ROUND_HALF_DOWN: {
- if (residue>5) bump=1;
- break;} /* r-h-d */
-
- case DEC_ROUND_HALF_EVEN: {
- if (residue>5) bump=1; /* >0.5 goes up */
- else if (residue==5) { /* exactly 0.5000... */
- /* 0.5 goes up iff [new] lsd is odd */
- if (*dn->lsu & 0x01) bump=1;
- }
- break;} /* r-h-e */
-
- case DEC_ROUND_HALF_UP: {
- if (residue>=5) bump=1;
- break;} /* r-h-u */
-
- case DEC_ROUND_UP: {
- if (residue>0) bump=1;
- break;} /* r-u */
-
- case DEC_ROUND_CEILING: {
- /* same as _UP for positive numbers, and as _DOWN for negatives */
- /* [negative residue cannot occur on 0] */
- if (decNumberIsNegative(dn)) {
- if (residue<0) bump=-1;
- }
- else {
- if (residue>0) bump=1;
- }
- break;} /* r-c */
-
- case DEC_ROUND_FLOOR: {
- /* same as _UP for negative numbers, and as _DOWN for positive */
- /* [negative residue cannot occur on 0] */
- if (!decNumberIsNegative(dn)) {
- if (residue<0) bump=-1;
- }
- else {
- if (residue>0) bump=1;
- }
- break;} /* r-f */
-
- default: { /* e.g., DEC_ROUND_MAX */
- *status|=DEC_Invalid_context;
- #if DECTRACE || (DECCHECK && DECVERB)
- printf("Unknown rounding mode: %d\n", set->round);
- #endif
- break;}
- } /* switch */
-
- /* now bump the number, up or down, if need be */
- if (bump==0) return; /* no action required */
-
- /* Simply use decUnitAddSub unless bumping up and the number is */
- /* all nines. In this special case set to 100... explicitly */
- /* and adjust the exponent by one (as otherwise could overflow */
- /* the array) */
- /* Similarly handle all-nines result if bumping down. */
- if (bump>0) {
- Unit *up; /* work */
- uInt count=dn->digits; /* digits to be checked */
- for (up=dn->lsu; ; up++) {
- if (count<=DECDPUN) {
- /* this is the last Unit (the msu) */
- if (*up!=powers[count]-1) break; /* not still 9s */
- /* here if it, too, is all nines */
- *up=(Unit)powers[count-1]; /* here 999 -> 100 etc. */
- for (up=up-1; up>=dn->lsu; up--) *up=0; /* others all to 0 */
- dn->exponent++; /* and bump exponent */
- /* [which, very rarely, could cause Overflow...] */
- if ((dn->exponent+dn->digits)>set->emax+1) {
- decSetOverflow(dn, set, status);
- }
- return; /* done */
- }
- /* a full unit to check, with more to come */
- if (*up!=DECDPUNMAX) break; /* not still 9s */
- count-=DECDPUN;
- } /* up */
- } /* bump>0 */
- else { /* -1 */
- /* here checking for a pre-bump of 1000... (leading 1, all */
- /* other digits zero) */
- Unit *up, *sup; /* work */
- uInt count=dn->digits; /* digits to be checked */
- for (up=dn->lsu; ; up++) {
- if (count<=DECDPUN) {
- /* this is the last Unit (the msu) */
- if (*up!=powers[count-1]) break; /* not 100.. */
- /* here if have the 1000... case */
- sup=up; /* save msu pointer */
- *up=(Unit)powers[count]-1; /* here 100 in msu -> 999 */
- /* others all to all-nines, too */
- for (up=up-1; up>=dn->lsu; up--) *up=(Unit)powers[DECDPUN]-1;
- dn->exponent--; /* and bump exponent */
-
- /* iff the number was at the subnormal boundary (exponent=etiny) */
- /* then the exponent is now out of range, so it will in fact get */
- /* clamped to etiny and the final 9 dropped. */
- /* printf(">> emin=%d exp=%d sdig=%d\n", set->emin, */
- /* dn->exponent, set->digits); */
- if (dn->exponent+1==set->emin-set->digits+1) {
- if (count==1 && dn->digits==1) *sup=0; /* here 9 -> 0[.9] */
- else {
- *sup=(Unit)powers[count-1]-1; /* here 999.. in msu -> 99.. */
- dn->digits--;
- }
- dn->exponent++;
- *status|=DEC_Underflow | DEC_Subnormal | DEC_Inexact | DEC_Rounded;
- }
- return; /* done */
- }
-
- /* a full unit to check, with more to come */
- if (*up!=0) break; /* not still 0s */
- count-=DECDPUN;
- } /* up */
-
- } /* bump<0 */
-
- /* Actual bump needed. Do it. */
- decUnitAddSub(dn->lsu, D2U(dn->digits), uarrone, 1, 0, dn->lsu, bump);
- } /* decApplyRound */
-
-#if DECSUBSET
-/* ------------------------------------------------------------------ */
-/* decFinish -- finish processing a number */
-/* */
-/* dn is the number */
-/* set is the context */
-/* residue is the rounding accumulator (as in decApplyRound) */
-/* status is the accumulator */
-/* */
-/* This finishes off the current number by: */
-/* 1. If not extended: */
-/* a. Converting a zero result to clean '0' */
-/* b. Reducing positive exponents to 0, if would fit in digits */
-/* 2. Checking for overflow and subnormals (always) */
-/* Note this is just Finalize when no subset arithmetic. */
-/* All fields are updated as required. */
-/* ------------------------------------------------------------------ */
-static void decFinish(decNumber *dn, decContext *set, Int *residue,
- uInt *status) {
- if (!set->extended) {
- if ISZERO(dn) { /* value is zero */
- dn->exponent=0; /* clean exponent .. */
- dn->bits=0; /* .. and sign */
- return; /* no error possible */
- }
- if (dn->exponent>=0) { /* non-negative exponent */
- /* >0; reduce to integer if possible */
- if (set->digits >= (dn->exponent+dn->digits)) {
- dn->digits=decShiftToMost(dn->lsu, dn->digits, dn->exponent);
- dn->exponent=0;
- }
- }
- } /* !extended */
-
- decFinalize(dn, set, residue, status);
- } /* decFinish */
-#endif
-
-/* ------------------------------------------------------------------ */
-/* decFinalize -- final check, clamp, and round of a number */
-/* */
-/* dn is the number */
-/* set is the context */
-/* residue is the rounding accumulator (as in decApplyRound) */
-/* status is the status accumulator */
-/* */
-/* This finishes off the current number by checking for subnormal */
-/* results, applying any pending rounding, checking for overflow, */
-/* and applying any clamping. */
-/* Underflow and overflow conditions are raised as appropriate. */
-/* All fields are updated as required. */
-/* ------------------------------------------------------------------ */
-static void decFinalize(decNumber *dn, decContext *set, Int *residue,
- uInt *status) {
- Int shift; /* shift needed if clamping */
- Int tinyexp=set->emin-dn->digits+1; /* precalculate subnormal boundary */
-
- /* Must be careful, here, when checking the exponent as the */
- /* adjusted exponent could overflow 31 bits [because it may already */
- /* be up to twice the expected]. */
-
- /* First test for subnormal. This must be done before any final */
- /* round as the result could be rounded to Nmin or 0. */
- if (dn->exponent<=tinyexp) { /* prefilter */
- Int comp;
- decNumber nmin;
- /* A very nasty case here is dn == Nmin and residue<0 */
- if (dn->exponent<tinyexp) {
- /* Go handle subnormals; this will apply round if needed. */
- decSetSubnormal(dn, set, residue, status);
- return;
- }
- /* Equals case: only subnormal if dn=Nmin and negative residue */
- uprv_decNumberZero(&nmin);
- nmin.lsu[0]=1;
- nmin.exponent=set->emin;
- comp=decCompare(dn, &nmin, 1); /* (signless compare) */
- if (comp==BADINT) { /* oops */
- *status|=DEC_Insufficient_storage; /* abandon... */
- return;
- }
- if (*residue<0 && comp==0) { /* neg residue and dn==Nmin */
- decApplyRound(dn, set, *residue, status); /* might force down */
- decSetSubnormal(dn, set, residue, status);
- return;
- }
- }
-
- /* now apply any pending round (this could raise overflow). */
- if (*residue!=0) decApplyRound(dn, set, *residue, status);
-
- /* Check for overflow [redundant in the 'rare' case] or clamp */
- if (dn->exponent<=set->emax-set->digits+1) return; /* neither needed */
-
-
- /* here when might have an overflow or clamp to do */
- if (dn->exponent>set->emax-dn->digits+1) { /* too big */
- decSetOverflow(dn, set, status);
- return;
- }
- /* here when the result is normal but in clamp range */
- if (!set->clamp) return;
-
- /* here when need to apply the IEEE exponent clamp (fold-down) */
- shift=dn->exponent-(set->emax-set->digits+1);
-
- /* shift coefficient (if non-zero) */
- if (!ISZERO(dn)) {
- dn->digits=decShiftToMost(dn->lsu, dn->digits, shift);
- }
- dn->exponent-=shift; /* adjust the exponent to match */
- *status|=DEC_Clamped; /* and record the dirty deed */
- return;
- } /* decFinalize */
-
-/* ------------------------------------------------------------------ */
-/* decSetOverflow -- set number to proper overflow value */
-/* */
-/* dn is the number (used for sign [only] and result) */
-/* set is the context [used for the rounding mode, etc.] */
-/* status contains the current status to be updated */
-/* */
-/* This sets the sign of a number and sets its value to either */
-/* Infinity or the maximum finite value, depending on the sign of */
-/* dn and the rounding mode, following IEEE 754 rules. */
-/* ------------------------------------------------------------------ */
-static void decSetOverflow(decNumber *dn, decContext *set, uInt *status) {
- Flag needmax=0; /* result is maximum finite value */
- uByte sign=dn->bits&DECNEG; /* clean and save sign bit */
-
- if (ISZERO(dn)) { /* zero does not overflow magnitude */
- Int emax=set->emax; /* limit value */
- if (set->clamp) emax-=set->digits-1; /* lower if clamping */
- if (dn->exponent>emax) { /* clamp required */
- dn->exponent=emax;
- *status|=DEC_Clamped;
- }
- return;
- }
-
- uprv_decNumberZero(dn);
- switch (set->round) {
- case DEC_ROUND_DOWN: {
- needmax=1; /* never Infinity */
- break;} /* r-d */
- case DEC_ROUND_05UP: {
- needmax=1; /* never Infinity */
- break;} /* r-05 */
- case DEC_ROUND_CEILING: {
- if (sign) needmax=1; /* Infinity if non-negative */
- break;} /* r-c */
- case DEC_ROUND_FLOOR: {
- if (!sign) needmax=1; /* Infinity if negative */
- break;} /* r-f */
- default: break; /* Infinity in all other cases */
- }
- if (needmax) {
- decSetMaxValue(dn, set);
- dn->bits=sign; /* set sign */
- }
- else dn->bits=sign|DECINF; /* Value is +/-Infinity */
- *status|=DEC_Overflow | DEC_Inexact | DEC_Rounded;
- } /* decSetOverflow */
-
-/* ------------------------------------------------------------------ */
-/* decSetMaxValue -- set number to +Nmax (maximum normal value) */
-/* */
-/* dn is the number to set */
-/* set is the context [used for digits and emax] */
-/* */
-/* This sets the number to the maximum positive value. */
-/* ------------------------------------------------------------------ */
-static void decSetMaxValue(decNumber *dn, decContext *set) {
- Unit *up; /* work */
- Int count=set->digits; /* nines to add */
- dn->digits=count;
- /* fill in all nines to set maximum value */
- for (up=dn->lsu; ; up++) {
- if (count>DECDPUN) *up=DECDPUNMAX; /* unit full o'nines */
- else { /* this is the msu */
- *up=(Unit)(powers[count]-1);
- break;
- }
- count-=DECDPUN; /* filled those digits */
- } /* up */
- dn->bits=0; /* + sign */
- dn->exponent=set->emax-set->digits+1;
- } /* decSetMaxValue */
-
-/* ------------------------------------------------------------------ */
-/* decSetSubnormal -- process value whose exponent is <Emin */
-/* */
-/* dn is the number (used as input as well as output; it may have */
-/* an allowed subnormal value, which may need to be rounded) */
-/* set is the context [used for the rounding mode] */
-/* residue is any pending residue */
-/* status contains the current status to be updated */
-/* */
-/* If subset mode, set result to zero and set Underflow flags. */
-/* */
-/* Value may be zero with a low exponent; this does not set Subnormal */
-/* but the exponent will be clamped to Etiny. */
-/* */
-/* Otherwise ensure exponent is not out of range, and round as */
-/* necessary. Underflow is set if the result is Inexact. */
-/* ------------------------------------------------------------------ */
-static void decSetSubnormal(decNumber *dn, decContext *set, Int *residue,
- uInt *status) {
- decContext workset; /* work */
- Int etiny, adjust; /* .. */
-
- #if DECSUBSET
- /* simple set to zero and 'hard underflow' for subset */
- if (!set->extended) {
- uprv_decNumberZero(dn);
- /* always full overflow */
- *status|=DEC_Underflow | DEC_Subnormal | DEC_Inexact | DEC_Rounded;
- return;
- }
- #endif
-
- /* Full arithmetic -- allow subnormals, rounded to minimum exponent */
- /* (Etiny) if needed */
- etiny=set->emin-(set->digits-1); /* smallest allowed exponent */
-
- if ISZERO(dn) { /* value is zero */
- /* residue can never be non-zero here */
- #if DECCHECK
- if (*residue!=0) {
- printf("++ Subnormal 0 residue %ld\n", (LI)*residue);
- *status|=DEC_Invalid_operation;
- }
- #endif
- if (dn->exponent<etiny) { /* clamp required */
- dn->exponent=etiny;
- *status|=DEC_Clamped;
- }
- return;
- }
-
- *status|=DEC_Subnormal; /* have a non-zero subnormal */
- adjust=etiny-dn->exponent; /* calculate digits to remove */
- if (adjust<=0) { /* not out of range; unrounded */
- /* residue can never be non-zero here, except in the Nmin-residue */
- /* case (which is a subnormal result), so can take fast-path here */
- /* it may already be inexact (from setting the coefficient) */
- if (*status&DEC_Inexact) *status|=DEC_Underflow;
- return;
- }
-
- /* adjust>0, so need to rescale the result so exponent becomes Etiny */
- /* [this code is similar to that in rescale] */
- workset=*set; /* clone rounding, etc. */
- workset.digits=dn->digits-adjust; /* set requested length */
- workset.emin-=adjust; /* and adjust emin to match */
- /* [note that the latter can be <1, here, similar to Rescale case] */
- decSetCoeff(dn, &workset, dn->lsu, dn->digits, residue, status);
- decApplyRound(dn, &workset, *residue, status);
-
- /* Use 754 default rule: Underflow is set iff Inexact */
- /* [independent of whether trapped] */
- if (*status&DEC_Inexact) *status|=DEC_Underflow;
-
- /* if rounded up a 999s case, exponent will be off by one; adjust */
- /* back if so [it will fit, because it was shortened earlier] */
- if (dn->exponent>etiny) {
- dn->digits=decShiftToMost(dn->lsu, dn->digits, 1);
- dn->exponent--; /* (re)adjust the exponent. */
- }
-
- /* if rounded to zero, it is by definition clamped... */
- if (ISZERO(dn)) *status|=DEC_Clamped;
- } /* decSetSubnormal */
-
-/* ------------------------------------------------------------------ */
-/* decCheckMath - check entry conditions for a math function */
-/* */
-/* This checks the context and the operand */
-/* */
-/* rhs is the operand to check */
-/* set is the context to check */
-/* status is unchanged if both are good */
-/* */
-/* returns non-zero if status is changed, 0 otherwise */
-/* */
-/* Restrictions enforced: */
-/* */
-/* digits, emax, and -emin in the context must be less than */
-/* DEC_MAX_MATH (999999), and A must be within these bounds if */
-/* non-zero. Invalid_operation is set in the status if a */
-/* restriction is violated. */
-/* ------------------------------------------------------------------ */
-static uInt decCheckMath(const decNumber *rhs, decContext *set,
- uInt *status) {
- uInt save=*status; /* record */
- if (set->digits>DEC_MAX_MATH
- || set->emax>DEC_MAX_MATH
- || -set->emin>DEC_MAX_MATH) *status|=DEC_Invalid_context;
- else if ((rhs->digits>DEC_MAX_MATH
- || rhs->exponent+rhs->digits>DEC_MAX_MATH+1
- || rhs->exponent+rhs->digits<2*(1-DEC_MAX_MATH))
- && !ISZERO(rhs)) *status|=DEC_Invalid_operation;
- return (*status!=save);
- } /* decCheckMath */
-
-/* ------------------------------------------------------------------ */
-/* decGetInt -- get integer from a number */
-/* */
-/* dn is the number [which will not be altered] */
-/* */
-/* returns one of: */
-/* BADINT if there is a non-zero fraction */
-/* the converted integer */
-/* BIGEVEN if the integer is even and magnitude > 2*10**9 */
-/* BIGODD if the integer is odd and magnitude > 2*10**9 */
-/* */
-/* This checks and gets a whole number from the input decNumber. */
-/* The sign can be determined from dn by the caller when BIGEVEN or */
-/* BIGODD is returned. */
-/* ------------------------------------------------------------------ */
-static Int decGetInt(const decNumber *dn) {
- Int theInt; /* result accumulator */
- const Unit *up; /* work */
- Int got; /* digits (real or not) processed */
- Int ilength=dn->digits+dn->exponent; /* integral length */
- Flag neg=decNumberIsNegative(dn); /* 1 if -ve */
-
- /* The number must be an integer that fits in 10 digits */
- /* Assert, here, that 10 is enough for any rescale Etiny */
- #if DEC_MAX_EMAX > 999999999
- #error GetInt may need updating [for Emax]
- #endif
- #if DEC_MIN_EMIN < -999999999
- #error GetInt may need updating [for Emin]
- #endif
- if (ISZERO(dn)) return 0; /* zeros are OK, with any exponent */
-
- up=dn->lsu; /* ready for lsu */
- theInt=0; /* ready to accumulate */
- if (dn->exponent>=0) { /* relatively easy */
- /* no fractional part [usual]; allow for positive exponent */
- got=dn->exponent;
- }
- else { /* -ve exponent; some fractional part to check and discard */
- Int count=-dn->exponent; /* digits to discard */
- /* spin up whole units until reach the Unit with the unit digit */
- for (; count>=DECDPUN; up++) {
- if (*up!=0) return BADINT; /* non-zero Unit to discard */
- count-=DECDPUN;
- }
- if (count==0) got=0; /* [a multiple of DECDPUN] */
- else { /* [not multiple of DECDPUN] */
- Int rem; /* work */
- /* slice off fraction digits and check for non-zero */
- #if DECDPUN<=4
- theInt=QUOT10(*up, count);
- rem=*up-theInt*powers[count];
- #else
- rem=*up%powers[count]; /* slice off discards */
- theInt=*up/powers[count];
- #endif
- if (rem!=0) return BADINT; /* non-zero fraction */
- /* it looks good */
- got=DECDPUN-count; /* number of digits so far */
- up++; /* ready for next */
- }
- }
- /* now it's known there's no fractional part */
-
- /* tricky code now, to accumulate up to 9.3 digits */
- if (got==0) {theInt=*up; got+=DECDPUN; up++;} /* ensure lsu is there */
-
- if (ilength<11) {
- Int save=theInt;
- /* collect any remaining unit(s) */
- for (; got<ilength; up++) {
- theInt+=*up*powers[got];
- got+=DECDPUN;
- }
- if (ilength==10) { /* need to check for wrap */
- if (theInt/(Int)powers[got-DECDPUN]!=(Int)*(up-1)) ilength=11;
- /* [that test also disallows the BADINT result case] */
- else if (neg && theInt>1999999997) ilength=11;
- else if (!neg && theInt>999999999) ilength=11;
- if (ilength==11) theInt=save; /* restore correct low bit */
- }
- }
-
- if (ilength>10) { /* too big */
- if (theInt&1) return BIGODD; /* bottom bit 1 */
- return BIGEVEN; /* bottom bit 0 */
- }
-
- if (neg) theInt=-theInt; /* apply sign */
- return theInt;
- } /* decGetInt */
-
-/* ------------------------------------------------------------------ */
-/* decDecap -- decapitate the coefficient of a number */
-/* */
-/* dn is the number to be decapitated */
-/* drop is the number of digits to be removed from the left of dn; */
-/* this must be <= dn->digits (if equal, the coefficient is */
-/* set to 0) */
-/* */
-/* Returns dn; dn->digits will be <= the initial digits less drop */
-/* (after removing drop digits there may be leading zero digits */
-/* which will also be removed). Only dn->lsu and dn->digits change. */
-/* ------------------------------------------------------------------ */
-static decNumber *decDecap(decNumber *dn, Int drop) {
- Unit *msu; /* -> target cut point */
- Int cut; /* work */
- if (drop>=dn->digits) { /* losing the whole thing */
- #if DECCHECK
- if (drop>dn->digits)
- printf("decDecap called with drop>digits [%ld>%ld]\n",
- (LI)drop, (LI)dn->digits);
- #endif
- dn->lsu[0]=0;
- dn->digits=1;
- return dn;
- }
- msu=dn->lsu+D2U(dn->digits-drop)-1; /* -> likely msu */
- cut=MSUDIGITS(dn->digits-drop); /* digits to be in use in msu */
- if (cut!=DECDPUN) *msu%=powers[cut]; /* clear left digits */
- /* that may have left leading zero digits, so do a proper count... */
- dn->digits=decGetDigits(dn->lsu, static_cast<int32_t>(msu-dn->lsu+1));
- return dn;
- } /* decDecap */
-
-/* ------------------------------------------------------------------ */
-/* decBiStr -- compare string with pairwise options */
-/* */
-/* targ is the string to compare */
-/* str1 is one of the strings to compare against (length may be 0) */
-/* str2 is the other; it must be the same length as str1 */
-/* */
-/* returns 1 if strings compare equal, (that is, it is the same */
-/* length as str1 and str2, and each character of targ is in either */
-/* str1 or str2 in the corresponding position), or 0 otherwise */
-/* */
-/* This is used for generic caseless compare, including the awkward */
-/* case of the Turkish dotted and dotless Is. Use as (for example): */
-/* if (decBiStr(test, "mike", "MIKE")) ... */
-/* ------------------------------------------------------------------ */
-static Flag decBiStr(const char *targ, const char *str1, const char *str2) {
- for (;;targ++, str1++, str2++) {
- if (*targ!=*str1 && *targ!=*str2) return 0;
- /* *targ has a match in one (or both, if terminator) */
- if (*targ=='\0') break;
- } /* forever */
- return 1;
- } /* decBiStr */
-
-/* ------------------------------------------------------------------ */
-/* decNaNs -- handle NaN operand or operands */
-/* */
-/* res is the result number */
-/* lhs is the first operand */
-/* rhs is the second operand, or NULL if none */
-/* context is used to limit payload length */
-/* status contains the current status */
-/* returns res in case convenient */
-/* */
-/* Called when one or both operands is a NaN, and propagates the */
-/* appropriate result to res. When an sNaN is found, it is changed */
-/* to a qNaN and Invalid operation is set. */
-/* ------------------------------------------------------------------ */
-static decNumber * decNaNs(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set,
- uInt *status) {
- /* This decision tree ends up with LHS being the source pointer, */
- /* and status updated if need be */
- if (lhs->bits & DECSNAN)
- *status|=DEC_Invalid_operation | DEC_sNaN;
- else if (rhs==NULL);
- else if (rhs->bits & DECSNAN) {
- lhs=rhs;
- *status|=DEC_Invalid_operation | DEC_sNaN;
- }
- else if (lhs->bits & DECNAN);
- else lhs=rhs;
-
- /* propagate the payload */
- if (lhs->digits<=set->digits) uprv_decNumberCopy(res, lhs); /* easy */
- else { /* too long */
- const Unit *ul;
- Unit *ur, *uresp1;
- /* copy safe number of units, then decapitate */
- res->bits=lhs->bits; /* need sign etc. */
- uresp1=res->lsu+D2U(set->digits);
- for (ur=res->lsu, ul=lhs->lsu; ur<uresp1; ur++, ul++) *ur=*ul;
- res->digits=D2U(set->digits)*DECDPUN;
- /* maybe still too long */
- if (res->digits>set->digits) decDecap(res, res->digits-set->digits);
- }
-
- res->bits&=~DECSNAN; /* convert any sNaN to NaN, while */
- res->bits|=DECNAN; /* .. preserving sign */
- res->exponent=0; /* clean exponent */
- /* [coefficient was copied/decapitated] */
- return res;
- } /* decNaNs */
-
-/* ------------------------------------------------------------------ */
-/* decStatus -- apply non-zero status */
-/* */
-/* dn is the number to set if error */
-/* status contains the current status (not yet in context) */
-/* set is the context */
-/* */
-/* If the status is an error status, the number is set to a NaN, */
-/* unless the error was an overflow, divide-by-zero, or underflow, */
-/* in which case the number will have already been set. */
-/* */
-/* The context status is then updated with the new status. Note that */
-/* this may raise a signal, so control may never return from this */
-/* routine (hence resources must be recovered before it is called). */
-/* ------------------------------------------------------------------ */
-static void decStatus(decNumber *dn, uInt status, decContext *set) {
- if (status & DEC_NaNs) { /* error status -> NaN */
- /* if cause was an sNaN, clear and propagate [NaN is already set up] */
- if (status & DEC_sNaN) status&=~DEC_sNaN;
- else {
- uprv_decNumberZero(dn); /* other error: clean throughout */
- dn->bits=DECNAN; /* and make a quiet NaN */
- }
- }
- uprv_decContextSetStatus(set, status); /* [may not return] */
- return;
- } /* decStatus */
-
-/* ------------------------------------------------------------------ */
-/* decGetDigits -- count digits in a Units array */
-/* */
-/* uar is the Unit array holding the number (this is often an */
-/* accumulator of some sort) */
-/* len is the length of the array in units [>=1] */
-/* */
-/* returns the number of (significant) digits in the array */
-/* */
-/* All leading zeros are excluded, except the last if the array has */
-/* only zero Units. */
-/* ------------------------------------------------------------------ */
-/* This may be called twice during some operations. */
-static Int decGetDigits(Unit *uar, Int len) {
- Unit *up=uar+(len-1); /* -> msu */
- Int digits=(len-1)*DECDPUN+1; /* possible digits excluding msu */
- #if DECDPUN>4
- uInt const *pow; /* work */
- #endif
- /* (at least 1 in final msu) */
- #if DECCHECK
- if (len<1) printf("decGetDigits called with len<1 [%ld]\n", (LI)len);
- #endif
-
- for (; up>=uar; up--) {
- if (*up==0) { /* unit is all 0s */
- if (digits==1) break; /* a zero has one digit */
- digits-=DECDPUN; /* adjust for 0 unit */
- continue;}
- /* found the first (most significant) non-zero Unit */
- #if DECDPUN>1 /* not done yet */
- if (*up<10) break; /* is 1-9 */
- digits++;
- #if DECDPUN>2 /* not done yet */
- if (*up<100) break; /* is 10-99 */
- digits++;
- #if DECDPUN>3 /* not done yet */
- if (*up<1000) break; /* is 100-999 */
- digits++;
- #if DECDPUN>4 /* count the rest ... */
- for (pow=&powers[4]; *up>=*pow; pow++) digits++;
- #endif
- #endif
- #endif
- #endif
- break;
- } /* up */
- return digits;
- } /* decGetDigits */
-
-#if DECTRACE | DECCHECK
-/* ------------------------------------------------------------------ */
-/* decNumberShow -- display a number [debug aid] */
-/* dn is the number to show */
-/* */
-/* Shows: sign, exponent, coefficient (msu first), digits */
-/* or: sign, special-value */
-/* ------------------------------------------------------------------ */
-/* this is public so other modules can use it */
-void uprv_decNumberShow(const decNumber *dn) {
- const Unit *up; /* work */
- uInt u, d; /* .. */
- Int cut; /* .. */
- char isign='+'; /* main sign */
- if (dn==NULL) {
- printf("NULL\n");
- return;}
- if (decNumberIsNegative(dn)) isign='-';
- printf(" >> %c ", isign);
- if (dn->bits&DECSPECIAL) { /* Is a special value */
- if (decNumberIsInfinite(dn)) printf("Infinity");
- else { /* a NaN */
- if (dn->bits&DECSNAN) printf("sNaN"); /* signalling NaN */
- else printf("NaN");
- }
- /* if coefficient and exponent are 0, no more to do */
- if (dn->exponent==0 && dn->digits==1 && *dn->lsu==0) {
- printf("\n");
- return;}
- /* drop through to report other information */
- printf(" ");
- }
-
- /* now carefully display the coefficient */
- up=dn->lsu+D2U(dn->digits)-1; /* msu */
- printf("%ld", (LI)*up);
- for (up=up-1; up>=dn->lsu; up--) {
- u=*up;
- printf(":");
- for (cut=DECDPUN-1; cut>=0; cut--) {
- d=u/powers[cut];
- u-=d*powers[cut];
- printf("%ld", (LI)d);
- } /* cut */
- } /* up */
- if (dn->exponent!=0) {
- char esign='+';
- if (dn->exponent<0) esign='-';
- printf(" E%c%ld", esign, (LI)abs(dn->exponent));
- }
- printf(" [%ld]\n", (LI)dn->digits);
- } /* decNumberShow */
-#endif
-
-#if DECTRACE || DECCHECK
-/* ------------------------------------------------------------------ */
-/* decDumpAr -- display a unit array [debug/check aid] */
-/* name is a single-character tag name */
-/* ar is the array to display */
-/* len is the length of the array in Units */
-/* ------------------------------------------------------------------ */
-static void decDumpAr(char name, const Unit *ar, Int len) {
- Int i;
- const char *spec;
- #if DECDPUN==9
- spec="%09d ";
- #elif DECDPUN==8
- spec="%08d ";
- #elif DECDPUN==7
- spec="%07d ";
- #elif DECDPUN==6
- spec="%06d ";
- #elif DECDPUN==5
- spec="%05d ";
- #elif DECDPUN==4
- spec="%04d ";
- #elif DECDPUN==3
- spec="%03d ";
- #elif DECDPUN==2
- spec="%02d ";
- #else
- spec="%d ";
- #endif
- printf(" :%c: ", name);
- for (i=len-1; i>=0; i--) {
- if (i==len-1) printf("%ld ", (LI)ar[i]);
- else printf(spec, ar[i]);
- }
- printf("\n");
- return;}
-#endif
-
-#if DECCHECK
-/* ------------------------------------------------------------------ */
-/* decCheckOperands -- check operand(s) to a routine */
-/* res is the result structure (not checked; it will be set to */
-/* quiet NaN if error found (and it is not NULL)) */
-/* lhs is the first operand (may be DECUNRESU) */
-/* rhs is the second (may be DECUNUSED) */
-/* set is the context (may be DECUNCONT) */
-/* returns 0 if both operands, and the context are clean, or 1 */
-/* otherwise (in which case the context will show an error, */
-/* unless NULL). Note that res is not cleaned; caller should */
-/* handle this so res=NULL case is safe. */
-/* The caller is expected to abandon immediately if 1 is returned. */
-/* ------------------------------------------------------------------ */
-static Flag decCheckOperands(decNumber *res, const decNumber *lhs,
- const decNumber *rhs, decContext *set) {
- Flag bad=0;
- if (set==NULL) { /* oops; hopeless */
- #if DECTRACE || DECVERB
- printf("Reference to context is NULL.\n");
- #endif
- bad=1;
- return 1;}
- else if (set!=DECUNCONT
- && (set->digits<1 || set->round>=DEC_ROUND_MAX)) {
- bad=1;
- #if DECTRACE || DECVERB
- printf("Bad context [digits=%ld round=%ld].\n",
- (LI)set->digits, (LI)set->round);
- #endif
- }
- else {
- if (res==NULL) {
- bad=1;
- #if DECTRACE
- /* this one not DECVERB as standard tests include NULL */
- printf("Reference to result is NULL.\n");
- #endif
- }
- if (!bad && lhs!=DECUNUSED) bad=(decCheckNumber(lhs));
- if (!bad && rhs!=DECUNUSED) bad=(decCheckNumber(rhs));
- }
- if (bad) {
- if (set!=DECUNCONT) uprv_decContextSetStatus(set, DEC_Invalid_operation);
- if (res!=DECUNRESU && res!=NULL) {
- uprv_decNumberZero(res);
- res->bits=DECNAN; /* qNaN */
- }
- }
- return bad;
- } /* decCheckOperands */
-
-/* ------------------------------------------------------------------ */
-/* decCheckNumber -- check a number */
-/* dn is the number to check */
-/* returns 0 if the number is clean, or 1 otherwise */
-/* */
-/* The number is considered valid if it could be a result from some */
-/* operation in some valid context. */
-/* ------------------------------------------------------------------ */
-static Flag decCheckNumber(const decNumber *dn) {
- const Unit *up; /* work */
- uInt maxuint; /* .. */
- Int ae, d, digits; /* .. */
- Int emin, emax; /* .. */
-
- if (dn==NULL) { /* hopeless */
- #if DECTRACE
- /* this one not DECVERB as standard tests include NULL */
- printf("Reference to decNumber is NULL.\n");
- #endif
- return 1;}
-
- /* check special values */
- if (dn->bits & DECSPECIAL) {
- if (dn->exponent!=0) {
- #if DECTRACE || DECVERB
- printf("Exponent %ld (not 0) for a special value [%02x].\n",
- (LI)dn->exponent, dn->bits);
- #endif
- return 1;}
-
- /* 2003.09.08: NaNs may now have coefficients, so next tests Inf only */
- if (decNumberIsInfinite(dn)) {
- if (dn->digits!=1) {
- #if DECTRACE || DECVERB
- printf("Digits %ld (not 1) for an infinity.\n", (LI)dn->digits);
- #endif
- return 1;}
- if (*dn->lsu!=0) {
- #if DECTRACE || DECVERB
- printf("LSU %ld (not 0) for an infinity.\n", (LI)*dn->lsu);
- #endif
- decDumpAr('I', dn->lsu, D2U(dn->digits));
- return 1;}
- } /* Inf */
- /* 2002.12.26: negative NaNs can now appear through proposed IEEE */
- /* concrete formats (decimal64, etc.). */
- return 0;
- }
-
- /* check the coefficient */
- if (dn->digits<1 || dn->digits>DECNUMMAXP) {
- #if DECTRACE || DECVERB
- printf("Digits %ld in number.\n", (LI)dn->digits);
- #endif
- return 1;}
-
- d=dn->digits;
-
- for (up=dn->lsu; d>0; up++) {
- if (d>DECDPUN) maxuint=DECDPUNMAX;
- else { /* reached the msu */
- maxuint=powers[d]-1;
- if (dn->digits>1 && *up<powers[d-1]) {
- #if DECTRACE || DECVERB
- printf("Leading 0 in number.\n");
- uprv_decNumberShow(dn);
- #endif
- return 1;}
- }
- if (*up>maxuint) {
- #if DECTRACE || DECVERB
- printf("Bad Unit [%08lx] in %ld-digit number at offset %ld [maxuint %ld].\n",
- (LI)*up, (LI)dn->digits, (LI)(up-dn->lsu), (LI)maxuint);
- #endif
- return 1;}
- d-=DECDPUN;
- }
-
- /* check the exponent. Note that input operands can have exponents */
- /* which are out of the set->emin/set->emax and set->digits range */
- /* (just as they can have more digits than set->digits). */
- ae=dn->exponent+dn->digits-1; /* adjusted exponent */
- emax=DECNUMMAXE;
- emin=DECNUMMINE;
- digits=DECNUMMAXP;
- if (ae<emin-(digits-1)) {
- #if DECTRACE || DECVERB
- printf("Adjusted exponent underflow [%ld].\n", (LI)ae);
- uprv_decNumberShow(dn);
- #endif
- return 1;}
- if (ae>+emax) {
- #if DECTRACE || DECVERB
- printf("Adjusted exponent overflow [%ld].\n", (LI)ae);
- uprv_decNumberShow(dn);
- #endif
- return 1;}
-
- return 0; /* it's OK */
- } /* decCheckNumber */
-
-/* ------------------------------------------------------------------ */
-/* decCheckInexact -- check a normal finite inexact result has digits */
-/* dn is the number to check */
-/* set is the context (for status and precision) */
-/* sets Invalid operation, etc., if some digits are missing */
-/* [this check is not made for DECSUBSET compilation or when */
-/* subnormal is not set] */
-/* ------------------------------------------------------------------ */
-static void decCheckInexact(const decNumber *dn, decContext *set) {
- #if !DECSUBSET && DECEXTFLAG
- if ((set->status & (DEC_Inexact|DEC_Subnormal))==DEC_Inexact
- && (set->digits!=dn->digits) && !(dn->bits & DECSPECIAL)) {
- #if DECTRACE || DECVERB
- printf("Insufficient digits [%ld] on normal Inexact result.\n",
- (LI)dn->digits);
- uprv_decNumberShow(dn);
- #endif
- uprv_decContextSetStatus(set, DEC_Invalid_operation);
- }
- #else
- /* next is a noop for quiet compiler */
- if (dn!=NULL && dn->digits==0) set->status|=DEC_Invalid_operation;
- #endif
- return;
- } /* decCheckInexact */
-#endif
-
-#if DECALLOC
-#undef malloc
-#undef free
-/* ------------------------------------------------------------------ */
-/* decMalloc -- accountable allocation routine */
-/* n is the number of bytes to allocate */
-/* */
-/* Semantics is the same as the stdlib malloc routine, but bytes */
-/* allocated are accounted for globally, and corruption fences are */
-/* added before and after the 'actual' storage. */
-/* ------------------------------------------------------------------ */
-/* This routine allocates storage with an extra twelve bytes; 8 are */
-/* at the start and hold: */
-/* 0-3 the original length requested */
-/* 4-7 buffer corruption detection fence (DECFENCE, x4) */
-/* The 4 bytes at the end also hold a corruption fence (DECFENCE, x4) */
-/* ------------------------------------------------------------------ */
-static void *decMalloc(size_t n) {
- uInt size=n+12; /* true size */
- void *alloc; /* -> allocated storage */
- uByte *b, *b0; /* work */
- uInt uiwork; /* for macros */
-
- alloc=malloc(size); /* -> allocated storage */
- if (alloc==NULL) return NULL; /* out of strorage */
- b0=(uByte *)alloc; /* as bytes */
- decAllocBytes+=n; /* account for storage */
- UBFROMUI(alloc, n); /* save n */
- /* printf(" alloc ++ dAB: %ld (%ld)\n", (LI)decAllocBytes, (LI)n); */
- for (b=b0+4; b<b0+8; b++) *b=DECFENCE;
- for (b=b0+n+8; b<b0+n+12; b++) *b=DECFENCE;
- return b0+8; /* -> play area */
- } /* decMalloc */
-
-/* ------------------------------------------------------------------ */
-/* decFree -- accountable free routine */
-/* alloc is the storage to free */
-/* */
-/* Semantics is the same as the stdlib malloc routine, except that */
-/* the global storage accounting is updated and the fences are */
-/* checked to ensure that no routine has written 'out of bounds'. */
-/* ------------------------------------------------------------------ */
-/* This routine first checks that the fences have not been corrupted. */
-/* It then frees the storage using the 'truw' storage address (that */
-/* is, offset by 8). */
-/* ------------------------------------------------------------------ */
-static void decFree(void *alloc) {
- uInt n; /* original length */
- uByte *b, *b0; /* work */
- uInt uiwork; /* for macros */
-
- if (alloc==NULL) return; /* allowed; it's a nop */
- b0=(uByte *)alloc; /* as bytes */
- b0-=8; /* -> true start of storage */
- n=UBTOUI(b0); /* lift length */
- for (b=b0+4; b<b0+8; b++) if (*b!=DECFENCE)
- printf("=== Corrupt byte [%02x] at offset %d from %ld ===\n", *b,
- b-b0-8, (LI)b0);
- for (b=b0+n+8; b<b0+n+12; b++) if (*b!=DECFENCE)
- printf("=== Corrupt byte [%02x] at offset +%d from %ld, n=%ld ===\n", *b,
- b-b0-8, (LI)b0, (LI)n);
- free(b0); /* drop the storage */
- decAllocBytes-=n; /* account for storage */
- /* printf(" free -- dAB: %d (%d)\n", decAllocBytes, -n); */
- } /* decFree */
-#define malloc(a) decMalloc(a)
-#define free(a) decFree(a)
-#endif
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/* ------------------------------------------------------------------ */
+/* Decimal Number arithmetic module */
+/* ------------------------------------------------------------------ */
+/* Copyright (c) IBM Corporation, 2000-2014. All rights reserved. */
+/* */
+/* This software is made available under the terms of the */
+/* ICU License -- ICU 1.8.1 and later. */
+/* */
+/* The description and User's Guide ("The decNumber C Library") for */
+/* this software is called decNumber.pdf. This document is */
+/* available, together with arithmetic and format specifications, */
+/* testcases, and Web links, on the General Decimal Arithmetic page. */
+/* */
+/* Please send comments, suggestions, and corrections to the author: */
+/* mfc@uk.ibm.com */
+/* Mike Cowlishaw, IBM Fellow */
+/* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */
+/* ------------------------------------------------------------------ */
+
+/* Modified version, for use from within ICU.
+ * Renamed public functions, to avoid an unwanted export of the
+ * standard names from the ICU library.
+ *
+ * Use ICU's uprv_malloc() and uprv_free()
+ *
+ * Revert comment syntax to plain C
+ *
+ * Remove a few compiler warnings.
+ */
+
+/* This module comprises the routines for arbitrary-precision General */
+/* Decimal Arithmetic as defined in the specification which may be */
+/* found on the General Decimal Arithmetic pages. It implements both */
+/* the full ('extended') arithmetic and the simpler ('subset') */
+/* arithmetic. */
+/* */
+/* Usage notes: */
+/* */
+/* 1. This code is ANSI C89 except: */
+/* */
+/* a) C99 line comments (double forward slash) are used. (Most C */
+/* compilers accept these. If yours does not, a simple script */
+/* can be used to convert them to ANSI C comments.) */
+/* */
+/* b) Types from C99 stdint.h are used. If you do not have this */
+/* header file, see the User's Guide section of the decNumber */
+/* documentation; this lists the necessary definitions. */
+/* */
+/* c) If DECDPUN>4 or DECUSE64=1, the C99 64-bit int64_t and */
+/* uint64_t types may be used. To avoid these, set DECUSE64=0 */
+/* and DECDPUN<=4 (see documentation). */
+/* */
+/* The code also conforms to C99 restrictions; in particular, */
+/* strict aliasing rules are observed. */
+/* */
+/* 2. The decNumber format which this library uses is optimized for */
+/* efficient processing of relatively short numbers; in particular */
+/* it allows the use of fixed sized structures and minimizes copy */
+/* and move operations. It does, however, support arbitrary */
+/* precision (up to 999,999,999 digits) and arbitrary exponent */
+/* range (Emax in the range 0 through 999,999,999 and Emin in the */
+/* range -999,999,999 through 0). Mathematical functions (for */
+/* example decNumberExp) as identified below are restricted more */
+/* tightly: digits, emax, and -emin in the context must be <= */
+/* DEC_MAX_MATH (999999), and their operand(s) must be within */
+/* these bounds. */
+/* */
+/* 3. Logical functions are further restricted; their operands must */
+/* be finite, positive, have an exponent of zero, and all digits */
+/* must be either 0 or 1. The result will only contain digits */
+/* which are 0 or 1 (and will have exponent=0 and a sign of 0). */
+/* */
+/* 4. Operands to operator functions are never modified unless they */
+/* are also specified to be the result number (which is always */
+/* permitted). Other than that case, operands must not overlap. */
+/* */
+/* 5. Error handling: the type of the error is ORed into the status */
+/* flags in the current context (decContext structure). The */
+/* SIGFPE signal is then raised if the corresponding trap-enabler */
+/* flag in the decContext is set (is 1). */
+/* */
+/* It is the responsibility of the caller to clear the status */
+/* flags as required. */
+/* */
+/* The result of any routine which returns a number will always */
+/* be a valid number (which may be a special value, such as an */
+/* Infinity or NaN). */
+/* */
+/* 6. The decNumber format is not an exchangeable concrete */
+/* representation as it comprises fields which may be machine- */
+/* dependent (packed or unpacked, or special length, for example). */
+/* Canonical conversions to and from strings are provided; other */
+/* conversions are available in separate modules. */
+/* */
+/* 7. Normally, input operands are assumed to be valid. Set DECCHECK */
+/* to 1 for extended operand checking (including NULL operands). */
+/* Results are undefined if a badly-formed structure (or a NULL */
+/* pointer to a structure) is provided, though with DECCHECK */
+/* enabled the operator routines are protected against exceptions. */
+/* (Except if the result pointer is NULL, which is unrecoverable.) */
+/* */
+/* However, the routines will never cause exceptions if they are */
+/* given well-formed operands, even if the value of the operands */
+/* is inappropriate for the operation and DECCHECK is not set. */
+/* (Except for SIGFPE, as and where documented.) */
+/* */
+/* 8. Subset arithmetic is available only if DECSUBSET is set to 1. */
+/* ------------------------------------------------------------------ */
+/* Implementation notes for maintenance of this module: */
+/* */
+/* 1. Storage leak protection: Routines which use malloc are not */
+/* permitted to use return for fastpath or error exits (i.e., */
+/* they follow strict structured programming conventions). */
+/* Instead they have a do{}while(0); construct surrounding the */
+/* code which is protected -- break may be used to exit this. */
+/* Other routines can safely use the return statement inline. */
+/* */
+/* Storage leak accounting can be enabled using DECALLOC. */
+/* */
+/* 2. All loops use the for(;;) construct. Any do construct does */
+/* not loop; it is for allocation protection as just described. */
+/* */
+/* 3. Setting status in the context must always be the very last */
+/* action in a routine, as non-0 status may raise a trap and hence */
+/* the call to set status may not return (if the handler uses long */
+/* jump). Therefore all cleanup must be done first. In general, */
+/* to achieve this status is accumulated and is only applied just */
+/* before return by calling decContextSetStatus (via decStatus). */
+/* */
+/* Routines which allocate storage cannot, in general, use the */
+/* 'top level' routines which could cause a non-returning */
+/* transfer of control. The decXxxxOp routines are safe (do not */
+/* call decStatus even if traps are set in the context) and should */
+/* be used instead (they are also a little faster). */
+/* */
+/* 4. Exponent checking is minimized by allowing the exponent to */
+/* grow outside its limits during calculations, provided that */
+/* the decFinalize function is called later. Multiplication and */
+/* division, and intermediate calculations in exponentiation, */
+/* require more careful checks because of the risk of 31-bit */
+/* overflow (the most negative valid exponent is -1999999997, for */
+/* a 999999999-digit number with adjusted exponent of -999999999). */
+/* */
+/* 5. Rounding is deferred until finalization of results, with any */
+/* 'off to the right' data being represented as a single digit */
+/* residue (in the range -1 through 9). This avoids any double- */
+/* rounding when more than one shortening takes place (for */
+/* example, when a result is subnormal). */
+/* */
+/* 6. The digits count is allowed to rise to a multiple of DECDPUN */
+/* during many operations, so whole Units are handled and exact */
+/* accounting of digits is not needed. The correct digits value */
+/* is found by decGetDigits, which accounts for leading zeros. */
+/* This must be called before any rounding if the number of digits */
+/* is not known exactly. */
+/* */
+/* 7. The multiply-by-reciprocal 'trick' is used for partitioning */
+/* numbers up to four digits, using appropriate constants. This */
+/* is not useful for longer numbers because overflow of 32 bits */
+/* would lead to 4 multiplies, which is almost as expensive as */
+/* a divide (unless a floating-point or 64-bit multiply is */
+/* assumed to be available). */
+/* */
+/* 8. Unusual abbreviations that may be used in the commentary: */
+/* lhs -- left hand side (operand, of an operation) */
+/* lsd -- least significant digit (of coefficient) */
+/* lsu -- least significant Unit (of coefficient) */
+/* msd -- most significant digit (of coefficient) */
+/* msi -- most significant item (in an array) */
+/* msu -- most significant Unit (of coefficient) */
+/* rhs -- right hand side (operand, of an operation) */
+/* +ve -- positive */
+/* -ve -- negative */
+/* ** -- raise to the power */
+/* ------------------------------------------------------------------ */
+
+#include <stdlib.h> /* for malloc, free, etc. */
+/* #include <stdio.h> */ /* for printf [if needed] */
+#include <string.h> /* for strcpy */
+#include <ctype.h> /* for lower */
+#include "cmemory.h" /* for uprv_malloc, etc., in ICU */
+#include "decNumber.h" /* base number library */
+#include "decNumberLocal.h" /* decNumber local types, etc. */
+#include "uassert.h"
+
+/* Constants */
+/* Public lookup table used by the D2U macro */
+static const uByte d2utable[DECMAXD2U+1]=D2UTABLE;
+
+#define DECVERB 1 /* set to 1 for verbose DECCHECK */
+#define powers DECPOWERS /* old internal name */
+
+/* Local constants */
+#define DIVIDE 0x80 /* Divide operators */
+#define REMAINDER 0x40 /* .. */
+#define DIVIDEINT 0x20 /* .. */
+#define REMNEAR 0x10 /* .. */
+#define COMPARE 0x01 /* Compare operators */
+#define COMPMAX 0x02 /* .. */
+#define COMPMIN 0x03 /* .. */
+#define COMPTOTAL 0x04 /* .. */
+#define COMPNAN 0x05 /* .. [NaN processing] */
+#define COMPSIG 0x06 /* .. [signaling COMPARE] */
+#define COMPMAXMAG 0x07 /* .. */
+#define COMPMINMAG 0x08 /* .. */
+
+#define DEC_sNaN 0x40000000 /* local status: sNaN signal */
+#define BADINT (Int)0x80000000 /* most-negative Int; error indicator */
+/* Next two indicate an integer >= 10**6, and its parity (bottom bit) */
+#define BIGEVEN (Int)0x80000002
+#define BIGODD (Int)0x80000003
+
+static const Unit uarrone[1]={1}; /* Unit array of 1, used for incrementing */
+
+/* ------------------------------------------------------------------ */
+/* round-for-reround digits */
+/* ------------------------------------------------------------------ */
+#if 0
+static const uByte DECSTICKYTAB[10]={1,1,2,3,4,6,6,7,8,9}; /* used if sticky */
+#endif
+
+/* ------------------------------------------------------------------ */
+/* Powers of ten (powers[n]==10**n, 0<=n<=9) */
+/* ------------------------------------------------------------------ */
+static const uInt DECPOWERS[10]={1, 10, 100, 1000, 10000, 100000, 1000000,
+ 10000000, 100000000, 1000000000};
+
+
+/* Granularity-dependent code */
+#if DECDPUN<=4
+ #define eInt Int /* extended integer */
+ #define ueInt uInt /* unsigned extended integer */
+ /* Constant multipliers for divide-by-power-of five using reciprocal */
+ /* multiply, after removing powers of 2 by shifting, and final shift */
+ /* of 17 [we only need up to **4] */
+ static const uInt multies[]={131073, 26215, 5243, 1049, 210};
+ /* QUOT10 -- macro to return the quotient of unit u divided by 10**n */
+ #define QUOT10(u, n) ((((uInt)(u)>>(n))*multies[n])>>17)
+#else
+ /* For DECDPUN>4 non-ANSI-89 64-bit types are needed. */
+ #if !DECUSE64
+ #error decNumber.c: DECUSE64 must be 1 when DECDPUN>4
+ #endif
+ #define eInt Long /* extended integer */
+ #define ueInt uLong /* unsigned extended integer */
+#endif
+
+/* Local routines */
+static decNumber * decAddOp(decNumber *, const decNumber *, const decNumber *,
+ decContext *, uByte, uInt *);
+static Flag decBiStr(const char *, const char *, const char *);
+static uInt decCheckMath(const decNumber *, decContext *, uInt *);
+static void decApplyRound(decNumber *, decContext *, Int, uInt *);
+static Int decCompare(const decNumber *lhs, const decNumber *rhs, Flag);
+static decNumber * decCompareOp(decNumber *, const decNumber *,
+ const decNumber *, decContext *,
+ Flag, uInt *);
+static void decCopyFit(decNumber *, const decNumber *, decContext *,
+ Int *, uInt *);
+static decNumber * decDecap(decNumber *, Int);
+static decNumber * decDivideOp(decNumber *, const decNumber *,
+ const decNumber *, decContext *, Flag, uInt *);
+static decNumber * decExpOp(decNumber *, const decNumber *,
+ decContext *, uInt *);
+static void decFinalize(decNumber *, decContext *, Int *, uInt *);
+static Int decGetDigits(Unit *, Int);
+static Int decGetInt(const decNumber *);
+static decNumber * decLnOp(decNumber *, const decNumber *,
+ decContext *, uInt *);
+static decNumber * decMultiplyOp(decNumber *, const decNumber *,
+ const decNumber *, decContext *,
+ uInt *);
+static decNumber * decNaNs(decNumber *, const decNumber *,
+ const decNumber *, decContext *, uInt *);
+static decNumber * decQuantizeOp(decNumber *, const decNumber *,
+ const decNumber *, decContext *, Flag,
+ uInt *);
+static void decReverse(Unit *, Unit *);
+static void decSetCoeff(decNumber *, decContext *, const Unit *,
+ Int, Int *, uInt *);
+static void decSetMaxValue(decNumber *, decContext *);
+static void decSetOverflow(decNumber *, decContext *, uInt *);
+static void decSetSubnormal(decNumber *, decContext *, Int *, uInt *);
+static Int decShiftToLeast(Unit *, Int, Int);
+static Int decShiftToMost(Unit *, Int, Int);
+static void decStatus(decNumber *, uInt, decContext *);
+static void decToString(const decNumber *, char[], Flag);
+static decNumber * decTrim(decNumber *, decContext *, Flag, Flag, Int *);
+static Int decUnitAddSub(const Unit *, Int, const Unit *, Int, Int,
+ Unit *, Int);
+static Int decUnitCompare(const Unit *, Int, const Unit *, Int, Int);
+
+#if !DECSUBSET
+/* decFinish == decFinalize when no subset arithmetic needed */
+#define decFinish(a,b,c,d) decFinalize(a,b,c,d)
+#else
+static void decFinish(decNumber *, decContext *, Int *, uInt *);
+static decNumber * decRoundOperand(const decNumber *, decContext *, uInt *);
+#endif
+
+/* Local macros */
+/* masked special-values bits */
+#define SPECIALARG (rhs->bits & DECSPECIAL)
+#define SPECIALARGS ((lhs->bits | rhs->bits) & DECSPECIAL)
+
+/* For use in ICU */
+#define malloc(a) uprv_malloc(a)
+#define free(a) uprv_free(a)
+
+/* Diagnostic macros, etc. */
+#if DECALLOC
+/* Handle malloc/free accounting. If enabled, our accountable routines */
+/* are used; otherwise the code just goes straight to the system malloc */
+/* and free routines. */
+#define malloc(a) decMalloc(a)
+#define free(a) decFree(a)
+#define DECFENCE 0x5a /* corruption detector */
+/* 'Our' malloc and free: */
+static void *decMalloc(size_t);
+static void decFree(void *);
+uInt decAllocBytes=0; /* count of bytes allocated */
+/* Note that DECALLOC code only checks for storage buffer overflow. */
+/* To check for memory leaks, the decAllocBytes variable must be */
+/* checked to be 0 at appropriate times (e.g., after the test */
+/* harness completes a set of tests). This checking may be unreliable */
+/* if the testing is done in a multi-thread environment. */
+#endif
+
+#if DECCHECK
+/* Optional checking routines. Enabling these means that decNumber */
+/* and decContext operands to operator routines are checked for */
+/* correctness. This roughly doubles the execution time of the */
+/* fastest routines (and adds 600+ bytes), so should not normally be */
+/* used in 'production'. */
+/* decCheckInexact is used to check that inexact results have a full */
+/* complement of digits (where appropriate -- this is not the case */
+/* for Quantize, for example) */
+#define DECUNRESU ((decNumber *)(void *)0xffffffff)
+#define DECUNUSED ((const decNumber *)(void *)0xffffffff)
+#define DECUNCONT ((decContext *)(void *)(0xffffffff))
+static Flag decCheckOperands(decNumber *, const decNumber *,
+ const decNumber *, decContext *);
+static Flag decCheckNumber(const decNumber *);
+static void decCheckInexact(const decNumber *, decContext *);
+#endif
+
+#if DECTRACE || DECCHECK
+/* Optional trace/debugging routines (may or may not be used) */
+void decNumberShow(const decNumber *); /* displays the components of a number */
+static void decDumpAr(char, const Unit *, Int);
+#endif
+
+/* ================================================================== */
+/* Conversions */
+/* ================================================================== */
+
+/* ------------------------------------------------------------------ */
+/* from-int32 -- conversion from Int or uInt */
+/* */
+/* dn is the decNumber to receive the integer */
+/* in or uin is the integer to be converted */
+/* returns dn */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberFromInt32(decNumber *dn, Int in) {
+ uInt unsig;
+ if (in>=0) unsig=in;
+ else { /* negative (possibly BADINT) */
+ if (in==BADINT) unsig=(uInt)1073741824*2; /* special case */
+ else unsig=-in; /* invert */
+ }
+ /* in is now positive */
+ uprv_decNumberFromUInt32(dn, unsig);
+ if (in<0) dn->bits=DECNEG; /* sign needed */
+ return dn;
+ } /* decNumberFromInt32 */
+
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberFromUInt32(decNumber *dn, uInt uin) {
+ Unit *up; /* work pointer */
+ uprv_decNumberZero(dn); /* clean */
+ if (uin==0) return dn; /* [or decGetDigits bad call] */
+ for (up=dn->lsu; uin>0; up++) {
+ *up=(Unit)(uin%(DECDPUNMAX+1));
+ uin=uin/(DECDPUNMAX+1);
+ }
+ dn->digits=decGetDigits(dn->lsu, static_cast<int32_t>(up - dn->lsu));
+ return dn;
+ } /* decNumberFromUInt32 */
+
+/* ------------------------------------------------------------------ */
+/* to-int32 -- conversion to Int or uInt */
+/* */
+/* dn is the decNumber to convert */
+/* set is the context for reporting errors */
+/* returns the converted decNumber, or 0 if Invalid is set */
+/* */
+/* Invalid is set if the decNumber does not have exponent==0 or if */
+/* it is a NaN, Infinite, or out-of-range. */
+/* ------------------------------------------------------------------ */
+U_CAPI Int U_EXPORT2 uprv_decNumberToInt32(const decNumber *dn, decContext *set) {
+ #if DECCHECK
+ if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0;
+ #endif
+
+ /* special or too many digits, or bad exponent */
+ if (dn->bits&DECSPECIAL || dn->digits>10 || dn->exponent!=0) ; /* bad */
+ else { /* is a finite integer with 10 or fewer digits */
+ Int d; /* work */
+ const Unit *up; /* .. */
+ uInt hi=0, lo; /* .. */
+ up=dn->lsu; /* -> lsu */
+ lo=*up; /* get 1 to 9 digits */
+ #if DECDPUN>1 /* split to higher */
+ hi=lo/10;
+ lo=lo%10;
+ #endif
+ up++;
+ /* collect remaining Units, if any, into hi */
+ for (d=DECDPUN; d<dn->digits; up++, d+=DECDPUN) hi+=*up*powers[d-1];
+ /* now low has the lsd, hi the remainder */
+ if (hi>214748364 || (hi==214748364 && lo>7)) { /* out of range? */
+ /* most-negative is a reprieve */
+ if (dn->bits&DECNEG && hi==214748364 && lo==8) return 0x80000000;
+ /* bad -- drop through */
+ }
+ else { /* in-range always */
+ Int i=X10(hi)+lo;
+ if (dn->bits&DECNEG) return -i;
+ return i;
+ }
+ } /* integer */
+ uprv_decContextSetStatus(set, DEC_Invalid_operation); /* [may not return] */
+ return 0;
+ } /* decNumberToInt32 */
+
+U_CAPI uInt U_EXPORT2 uprv_decNumberToUInt32(const decNumber *dn, decContext *set) {
+ #if DECCHECK
+ if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0;
+ #endif
+ /* special or too many digits, or bad exponent, or negative (<0) */
+ if (dn->bits&DECSPECIAL || dn->digits>10 || dn->exponent!=0
+ || (dn->bits&DECNEG && !ISZERO(dn))); /* bad */
+ else { /* is a finite integer with 10 or fewer digits */
+ Int d; /* work */
+ const Unit *up; /* .. */
+ uInt hi=0, lo; /* .. */
+ up=dn->lsu; /* -> lsu */
+ lo=*up; /* get 1 to 9 digits */
+ #if DECDPUN>1 /* split to higher */
+ hi=lo/10;
+ lo=lo%10;
+ #endif
+ up++;
+ /* collect remaining Units, if any, into hi */
+ for (d=DECDPUN; d<dn->digits; up++, d+=DECDPUN) hi+=*up*powers[d-1];
+
+ /* now low has the lsd, hi the remainder */
+ if (hi>429496729 || (hi==429496729 && lo>5)) ; /* no reprieve possible */
+ else return X10(hi)+lo;
+ } /* integer */
+ uprv_decContextSetStatus(set, DEC_Invalid_operation); /* [may not return] */
+ return 0;
+ } /* decNumberToUInt32 */
+
+/* ------------------------------------------------------------------ */
+/* to-scientific-string -- conversion to numeric string */
+/* to-engineering-string -- conversion to numeric string */
+/* */
+/* decNumberToString(dn, string); */
+/* decNumberToEngString(dn, string); */
+/* */
+/* dn is the decNumber to convert */
+/* string is the string where the result will be laid out */
+/* */
+/* string must be at least dn->digits+14 characters long */
+/* */
+/* No error is possible, and no status can be set. */
+/* ------------------------------------------------------------------ */
+U_CAPI char * U_EXPORT2 uprv_decNumberToString(const decNumber *dn, char *string){
+ decToString(dn, string, 0);
+ return string;
+ } /* DecNumberToString */
+
+U_CAPI char * U_EXPORT2 uprv_decNumberToEngString(const decNumber *dn, char *string){
+ decToString(dn, string, 1);
+ return string;
+ } /* DecNumberToEngString */
+
+/* ------------------------------------------------------------------ */
+/* to-number -- conversion from numeric string */
+/* */
+/* decNumberFromString -- convert string to decNumber */
+/* dn -- the number structure to fill */
+/* chars[] -- the string to convert ('\0' terminated) */
+/* set -- the context used for processing any error, */
+/* determining the maximum precision available */
+/* (set.digits), determining the maximum and minimum */
+/* exponent (set.emax and set.emin), determining if */
+/* extended values are allowed, and checking the */
+/* rounding mode if overflow occurs or rounding is */
+/* needed. */
+/* */
+/* The length of the coefficient and the size of the exponent are */
+/* checked by this routine, so the correct error (Underflow or */
+/* Overflow) can be reported or rounding applied, as necessary. */
+/* */
+/* If bad syntax is detected, the result will be a quiet NaN. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberFromString(decNumber *dn, const char chars[],
+ decContext *set) {
+ Int exponent=0; /* working exponent [assume 0] */
+ uByte bits=0; /* working flags [assume +ve] */
+ Unit *res; /* where result will be built */
+ Unit resbuff[SD2U(DECBUFFER+9)];/* local buffer in case need temporary */
+ /* [+9 allows for ln() constants] */
+ Unit *allocres=NULL; /* -> allocated result, iff allocated */
+ Int d=0; /* count of digits found in decimal part */
+ const char *dotchar=NULL; /* where dot was found */
+ const char *cfirst=chars; /* -> first character of decimal part */
+ const char *last=NULL; /* -> last digit of decimal part */
+ const char *c; /* work */
+ Unit *up; /* .. */
+ #if DECDPUN>1
+ Int cut, out; /* .. */
+ #endif
+ Int residue; /* rounding residue */
+ uInt status=0; /* error code */
+
+ #if DECCHECK
+ if (decCheckOperands(DECUNRESU, DECUNUSED, DECUNUSED, set))
+ return uprv_decNumberZero(dn);
+ #endif
+
+ do { /* status & malloc protection */
+ for (c=chars;; c++) { /* -> input character */
+ if (*c>='0' && *c<='9') { /* test for Arabic digit */
+ last=c;
+ d++; /* count of real digits */
+ continue; /* still in decimal part */
+ }
+ if (*c=='.' && dotchar==NULL) { /* first '.' */
+ dotchar=c; /* record offset into decimal part */
+ if (c==cfirst) cfirst++; /* first digit must follow */
+ continue;}
+ if (c==chars) { /* first in string... */
+ if (*c=='-') { /* valid - sign */
+ cfirst++;
+ bits=DECNEG;
+ continue;}
+ if (*c=='+') { /* valid + sign */
+ cfirst++;
+ continue;}
+ }
+ /* *c is not a digit, or a valid +, -, or '.' */
+ break;
+ } /* c */
+
+ if (last==NULL) { /* no digits yet */
+ status=DEC_Conversion_syntax;/* assume the worst */
+ if (*c=='\0') break; /* and no more to come... */
+ #if DECSUBSET
+ /* if subset then infinities and NaNs are not allowed */
+ if (!set->extended) break; /* hopeless */
+ #endif
+ /* Infinities and NaNs are possible, here */
+ if (dotchar!=NULL) break; /* .. unless had a dot */
+ uprv_decNumberZero(dn); /* be optimistic */
+ if (decBiStr(c, "infinity", "INFINITY")
+ || decBiStr(c, "inf", "INF")) {
+ dn->bits=bits | DECINF;
+ status=0; /* is OK */
+ break; /* all done */
+ }
+ /* a NaN expected */
+ /* 2003.09.10 NaNs are now permitted to have a sign */
+ dn->bits=bits | DECNAN; /* assume simple NaN */
+ if (*c=='s' || *c=='S') { /* looks like an sNaN */
+ c++;
+ dn->bits=bits | DECSNAN;
+ }
+ if (*c!='n' && *c!='N') break; /* check caseless "NaN" */
+ c++;
+ if (*c!='a' && *c!='A') break; /* .. */
+ c++;
+ if (*c!='n' && *c!='N') break; /* .. */
+ c++;
+ /* now either nothing, or nnnn payload, expected */
+ /* -> start of integer and skip leading 0s [including plain 0] */
+ for (cfirst=c; *cfirst=='0';) cfirst++;
+ if (*cfirst=='\0') { /* "NaN" or "sNaN", maybe with all 0s */
+ status=0; /* it's good */
+ break; /* .. */
+ }
+ /* something other than 0s; setup last and d as usual [no dots] */
+ for (c=cfirst;; c++, d++) {
+ if (*c<'0' || *c>'9') break; /* test for Arabic digit */
+ last=c;
+ }
+ if (*c!='\0') break; /* not all digits */
+ if (d>set->digits-1) {
+ /* [NB: payload in a decNumber can be full length unless */
+ /* clamped, in which case can only be digits-1] */
+ if (set->clamp) break;
+ if (d>set->digits) break;
+ } /* too many digits? */
+ /* good; drop through to convert the integer to coefficient */
+ status=0; /* syntax is OK */
+ bits=dn->bits; /* for copy-back */
+ } /* last==NULL */
+
+ else if (*c!='\0') { /* more to process... */
+ /* had some digits; exponent is only valid sequence now */
+ Flag nege; /* 1=negative exponent */
+ const char *firstexp; /* -> first significant exponent digit */
+ status=DEC_Conversion_syntax;/* assume the worst */
+ if (*c!='e' && *c!='E') break;
+ /* Found 'e' or 'E' -- now process explicit exponent */
+ /* 1998.07.11: sign no longer required */
+ nege=0;
+ c++; /* to (possible) sign */
+ if (*c=='-') {nege=1; c++;}
+ else if (*c=='+') c++;
+ if (*c=='\0') break;
+
+ for (; *c=='0' && *(c+1)!='\0';) c++; /* strip insignificant zeros */
+ firstexp=c; /* save exponent digit place */
+ uInt uexponent = 0; /* Avoid undefined behavior on signed int overflow */
+ for (; ;c++) {
+ if (*c<'0' || *c>'9') break; /* not a digit */
+ uexponent=X10(uexponent)+(uInt)*c-(uInt)'0';
+ } /* c */
+ exponent = (Int)uexponent;
+ /* if not now on a '\0', *c must not be a digit */
+ if (*c!='\0') break;
+
+ /* (this next test must be after the syntax checks) */
+ /* if it was too long the exponent may have wrapped, so check */
+ /* carefully and set it to a certain overflow if wrap possible */
+ if (c>=firstexp+9+1) {
+ if (c>firstexp+9+1 || *firstexp>'1') exponent=DECNUMMAXE*2;
+ /* [up to 1999999999 is OK, for example 1E-1000000998] */
+ }
+ if (nege) exponent=-exponent; /* was negative */
+ status=0; /* is OK */
+ } /* stuff after digits */
+
+ /* Here when whole string has been inspected; syntax is good */
+ /* cfirst->first digit (never dot), last->last digit (ditto) */
+
+ /* strip leading zeros/dot [leave final 0 if all 0's] */
+ if (*cfirst=='0') { /* [cfirst has stepped over .] */
+ for (c=cfirst; c<last; c++, cfirst++) {
+ if (*c=='.') continue; /* ignore dots */
+ if (*c!='0') break; /* non-zero found */
+ d--; /* 0 stripped */
+ } /* c */
+ #if DECSUBSET
+ /* make a rapid exit for easy zeros if !extended */
+ if (*cfirst=='0' && !set->extended) {
+ uprv_decNumberZero(dn); /* clean result */
+ break; /* [could be return] */
+ }
+ #endif
+ } /* at least one leading 0 */
+
+ /* Handle decimal point... */
+ if (dotchar!=NULL && dotchar<last) /* non-trailing '.' found? */
+ exponent -= static_cast<int32_t>(last-dotchar); /* adjust exponent */
+ /* [we can now ignore the .] */
+
+ /* OK, the digits string is good. Assemble in the decNumber, or in */
+ /* a temporary units array if rounding is needed */
+ if (d<=set->digits) res=dn->lsu; /* fits into supplied decNumber */
+ else { /* rounding needed */
+ Int needbytes=D2U(d)*sizeof(Unit);/* bytes needed */
+ res=resbuff; /* assume use local buffer */
+ if (needbytes>(Int)sizeof(resbuff)) { /* too big for local */
+ allocres=(Unit *)malloc(needbytes);
+ if (allocres==NULL) {status|=DEC_Insufficient_storage; break;}
+ res=allocres;
+ }
+ }
+ /* res now -> number lsu, buffer, or allocated storage for Unit array */
+
+ /* Place the coefficient into the selected Unit array */
+ /* [this is often 70% of the cost of this function when DECDPUN>1] */
+ #if DECDPUN>1
+ out=0; /* accumulator */
+ up=res+D2U(d)-1; /* -> msu */
+ cut=d-(up-res)*DECDPUN; /* digits in top unit */
+ for (c=cfirst;; c++) { /* along the digits */
+ if (*c=='.') continue; /* ignore '.' [don't decrement cut] */
+ out=X10(out)+(Int)*c-(Int)'0';
+ if (c==last) break; /* done [never get to trailing '.'] */
+ cut--;
+ if (cut>0) continue; /* more for this unit */
+ *up=(Unit)out; /* write unit */
+ up--; /* prepare for unit below.. */
+ cut=DECDPUN; /* .. */
+ out=0; /* .. */
+ } /* c */
+ *up=(Unit)out; /* write lsu */
+
+ #else
+ /* DECDPUN==1 */
+ up=res; /* -> lsu */
+ for (c=last; c>=cfirst; c--) { /* over each character, from least */
+ if (*c=='.') continue; /* ignore . [don't step up] */
+ *up=(Unit)((Int)*c-(Int)'0');
+ up++;
+ } /* c */
+ #endif
+
+ dn->bits=bits;
+ dn->exponent=exponent;
+ dn->digits=d;
+
+ /* if not in number (too long) shorten into the number */
+ if (d>set->digits) {
+ residue=0;
+ decSetCoeff(dn, set, res, d, &residue, &status);
+ /* always check for overflow or subnormal and round as needed */
+ decFinalize(dn, set, &residue, &status);
+ }
+ else { /* no rounding, but may still have overflow or subnormal */
+ /* [these tests are just for performance; finalize repeats them] */
+ if ((dn->exponent-1<set->emin-dn->digits)
+ || (dn->exponent-1>set->emax-set->digits)) {
+ residue=0;
+ decFinalize(dn, set, &residue, &status);
+ }
+ }
+ /* decNumberShow(dn); */
+ } while(0); /* [for break] */
+
+ if (allocres!=NULL) free(allocres); /* drop any storage used */
+ if (status!=0) decStatus(dn, status, set);
+ return dn;
+ } /* decNumberFromString */
+
+/* ================================================================== */
+/* Operators */
+/* ================================================================== */
+
+/* ------------------------------------------------------------------ */
+/* decNumberAbs -- absolute value operator */
+/* */
+/* This computes C = abs(A) */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context */
+/* */
+/* See also decNumberCopyAbs for a quiet bitwise version of this. */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+/* This has the same effect as decNumberPlus unless A is negative, */
+/* in which case it has the same effect as decNumberMinus. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberAbs(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ decNumber dzero; /* for 0 */
+ uInt status=0; /* accumulator */
+
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ uprv_decNumberZero(&dzero); /* set 0 */
+ dzero.exponent=rhs->exponent; /* [no coefficient expansion] */
+ decAddOp(res, &dzero, rhs, set, (uByte)(rhs->bits & DECNEG), &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberAbs */
+
+/* ------------------------------------------------------------------ */
+/* decNumberAdd -- add two Numbers */
+/* */
+/* This computes C = A + B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X+X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+/* This just calls the routine shared with Subtract */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberAdd(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decAddOp(res, lhs, rhs, set, 0, &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberAdd */
+
+/* ------------------------------------------------------------------ */
+/* decNumberAnd -- AND two Numbers, digitwise */
+/* */
+/* This computes C = A & B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X&X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context (used for result length and error report) */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* Logical function restrictions apply (see above); a NaN is */
+/* returned with Invalid_operation if a restriction is violated. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberAnd(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ const Unit *ua, *ub; /* -> operands */
+ const Unit *msua, *msub; /* -> operand msus */
+ Unit *uc, *msuc; /* -> result and its msu */
+ Int msudigs; /* digits in res msu */
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ if (lhs->exponent!=0 || decNumberIsSpecial(lhs) || decNumberIsNegative(lhs)
+ || rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) {
+ decStatus(res, DEC_Invalid_operation, set);
+ return res;
+ }
+
+ /* operands are valid */
+ ua=lhs->lsu; /* bottom-up */
+ ub=rhs->lsu; /* .. */
+ uc=res->lsu; /* .. */
+ msua=ua+D2U(lhs->digits)-1; /* -> msu of lhs */
+ msub=ub+D2U(rhs->digits)-1; /* -> msu of rhs */
+ msuc=uc+D2U(set->digits)-1; /* -> msu of result */
+ msudigs=MSUDIGITS(set->digits); /* [faster than remainder] */
+ for (; uc<=msuc; ua++, ub++, uc++) { /* Unit loop */
+ Unit a, b; /* extract units */
+ if (ua>msua) a=0;
+ else a=*ua;
+ if (ub>msub) b=0;
+ else b=*ub;
+ *uc=0; /* can now write back */
+ if (a|b) { /* maybe 1 bits to examine */
+ Int i, j;
+ *uc=0; /* can now write back */
+ /* This loop could be unrolled and/or use BIN2BCD tables */
+ for (i=0; i<DECDPUN; i++) {
+ if (a&b&1) *uc=*uc+(Unit)powers[i]; /* effect AND */
+ j=a%10;
+ a=a/10;
+ j|=b%10;
+ b=b/10;
+ if (j>1) {
+ decStatus(res, DEC_Invalid_operation, set);
+ return res;
+ }
+ if (uc==msuc && i==msudigs-1) break; /* just did final digit */
+ } /* each digit */
+ } /* both OK */
+ } /* each unit */
+ /* [here uc-1 is the msu of the result] */
+ res->digits=decGetDigits(res->lsu, static_cast<int32_t>(uc - res->lsu));
+ res->exponent=0; /* integer */
+ res->bits=0; /* sign=0 */
+ return res; /* [no status to set] */
+ } /* decNumberAnd */
+
+/* ------------------------------------------------------------------ */
+/* decNumberCompare -- compare two Numbers */
+/* */
+/* This computes C = A ? B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for one digit (or NaN). */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberCompare(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decCompareOp(res, lhs, rhs, set, COMPARE, &status);
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberCompare */
+
+/* ------------------------------------------------------------------ */
+/* decNumberCompareSignal -- compare, signalling on all NaNs */
+/* */
+/* This computes C = A ? B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for one digit (or NaN). */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberCompareSignal(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decCompareOp(res, lhs, rhs, set, COMPSIG, &status);
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberCompareSignal */
+
+/* ------------------------------------------------------------------ */
+/* decNumberCompareTotal -- compare two Numbers, using total ordering */
+/* */
+/* This computes C = A ? B, under total ordering */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for one digit; the result will always be one of */
+/* -1, 0, or 1. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberCompareTotal(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decCompareOp(res, lhs, rhs, set, COMPTOTAL, &status);
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberCompareTotal */
+
+/* ------------------------------------------------------------------ */
+/* decNumberCompareTotalMag -- compare, total ordering of magnitudes */
+/* */
+/* This computes C = |A| ? |B|, under total ordering */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for one digit; the result will always be one of */
+/* -1, 0, or 1. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberCompareTotalMag(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ uInt needbytes; /* for space calculations */
+ decNumber bufa[D2N(DECBUFFER+1)];/* +1 in case DECBUFFER=0 */
+ decNumber *allocbufa=NULL; /* -> allocated bufa, iff allocated */
+ decNumber bufb[D2N(DECBUFFER+1)];
+ decNumber *allocbufb=NULL; /* -> allocated bufb, iff allocated */
+ decNumber *a, *b; /* temporary pointers */
+
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ do { /* protect allocated storage */
+ /* if either is negative, take a copy and absolute */
+ if (decNumberIsNegative(lhs)) { /* lhs<0 */
+ a=bufa;
+ needbytes=sizeof(decNumber)+(D2U(lhs->digits)-1)*sizeof(Unit);
+ if (needbytes>sizeof(bufa)) { /* need malloc space */
+ allocbufa=(decNumber *)malloc(needbytes);
+ if (allocbufa==NULL) { /* hopeless -- abandon */
+ status|=DEC_Insufficient_storage;
+ break;}
+ a=allocbufa; /* use the allocated space */
+ }
+ uprv_decNumberCopy(a, lhs); /* copy content */
+ a->bits&=~DECNEG; /* .. and clear the sign */
+ lhs=a; /* use copy from here on */
+ }
+ if (decNumberIsNegative(rhs)) { /* rhs<0 */
+ b=bufb;
+ needbytes=sizeof(decNumber)+(D2U(rhs->digits)-1)*sizeof(Unit);
+ if (needbytes>sizeof(bufb)) { /* need malloc space */
+ allocbufb=(decNumber *)malloc(needbytes);
+ if (allocbufb==NULL) { /* hopeless -- abandon */
+ status|=DEC_Insufficient_storage;
+ break;}
+ b=allocbufb; /* use the allocated space */
+ }
+ uprv_decNumberCopy(b, rhs); /* copy content */
+ b->bits&=~DECNEG; /* .. and clear the sign */
+ rhs=b; /* use copy from here on */
+ }
+ decCompareOp(res, lhs, rhs, set, COMPTOTAL, &status);
+ } while(0); /* end protected */
+
+ if (allocbufa!=NULL) free(allocbufa); /* drop any storage used */
+ if (allocbufb!=NULL) free(allocbufb); /* .. */
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberCompareTotalMag */
+
+/* ------------------------------------------------------------------ */
+/* decNumberDivide -- divide one number by another */
+/* */
+/* This computes C = A / B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X/X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberDivide(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decDivideOp(res, lhs, rhs, set, DIVIDE, &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberDivide */
+
+/* ------------------------------------------------------------------ */
+/* decNumberDivideInteger -- divide and return integer quotient */
+/* */
+/* This computes C = A # B, where # is the integer divide operator */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X#X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberDivideInteger(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decDivideOp(res, lhs, rhs, set, DIVIDEINT, &status);
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberDivideInteger */
+
+/* ------------------------------------------------------------------ */
+/* decNumberExp -- exponentiation */
+/* */
+/* This computes C = exp(A) */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context; note that rounding mode has no effect */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* Mathematical function restrictions apply (see above); a NaN is */
+/* returned with Invalid_operation if a restriction is violated. */
+/* */
+/* Finite results will always be full precision and Inexact, except */
+/* when A is a zero or -Infinity (giving 1 or 0 respectively). */
+/* */
+/* An Inexact result is rounded using DEC_ROUND_HALF_EVEN; it will */
+/* almost always be correctly rounded, but may be up to 1 ulp in */
+/* error in rare cases. */
+/* ------------------------------------------------------------------ */
+/* This is a wrapper for decExpOp which can handle the slightly wider */
+/* (double) range needed by Ln (which has to be able to calculate */
+/* exp(-a) where a can be the tiniest number (Ntiny). */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberExp(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ uInt status=0; /* accumulator */
+ #if DECSUBSET
+ decNumber *allocrhs=NULL; /* non-NULL if rounded rhs allocated */
+ #endif
+
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ /* Check restrictions; these restrictions ensure that if h=8 (see */
+ /* decExpOp) then the result will either overflow or underflow to 0. */
+ /* Other math functions restrict the input range, too, for inverses. */
+ /* If not violated then carry out the operation. */
+ if (!decCheckMath(rhs, set, &status)) do { /* protect allocation */
+ #if DECSUBSET
+ if (!set->extended) {
+ /* reduce operand and set lostDigits status, as needed */
+ if (rhs->digits>set->digits) {
+ allocrhs=decRoundOperand(rhs, set, &status);
+ if (allocrhs==NULL) break;
+ rhs=allocrhs;
+ }
+ }
+ #endif
+ decExpOp(res, rhs, set, &status);
+ } while(0); /* end protected */
+
+ #if DECSUBSET
+ if (allocrhs !=NULL) free(allocrhs); /* drop any storage used */
+ #endif
+ /* apply significant status */
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberExp */
+
+/* ------------------------------------------------------------------ */
+/* decNumberFMA -- fused multiply add */
+/* */
+/* This computes D = (A * B) + C with only one rounding */
+/* */
+/* res is D, the result. D may be A or B or C (e.g., X=FMA(X,X,X)) */
+/* lhs is A */
+/* rhs is B */
+/* fhs is C [far hand side] */
+/* set is the context */
+/* */
+/* Mathematical function restrictions apply (see above); a NaN is */
+/* returned with Invalid_operation if a restriction is violated. */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberFMA(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, const decNumber *fhs,
+ decContext *set) {
+ uInt status=0; /* accumulator */
+ decContext dcmul; /* context for the multiplication */
+ uInt needbytes; /* for space calculations */
+ decNumber bufa[D2N(DECBUFFER*2+1)];
+ decNumber *allocbufa=NULL; /* -> allocated bufa, iff allocated */
+ decNumber *acc; /* accumulator pointer */
+ decNumber dzero; /* work */
+
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ if (decCheckOperands(res, fhs, DECUNUSED, set)) return res;
+ #endif
+
+ do { /* protect allocated storage */
+ #if DECSUBSET
+ if (!set->extended) { /* [undefined if subset] */
+ status|=DEC_Invalid_operation;
+ break;}
+ #endif
+ /* Check math restrictions [these ensure no overflow or underflow] */
+ if ((!decNumberIsSpecial(lhs) && decCheckMath(lhs, set, &status))
+ || (!decNumberIsSpecial(rhs) && decCheckMath(rhs, set, &status))
+ || (!decNumberIsSpecial(fhs) && decCheckMath(fhs, set, &status))) break;
+ /* set up context for multiply */
+ dcmul=*set;
+ dcmul.digits=lhs->digits+rhs->digits; /* just enough */
+ /* [The above may be an over-estimate for subset arithmetic, but that's OK] */
+ dcmul.emax=DEC_MAX_EMAX; /* effectively unbounded .. */
+ dcmul.emin=DEC_MIN_EMIN; /* [thanks to Math restrictions] */
+ /* set up decNumber space to receive the result of the multiply */
+ acc=bufa; /* may fit */
+ needbytes=sizeof(decNumber)+(D2U(dcmul.digits)-1)*sizeof(Unit);
+ if (needbytes>sizeof(bufa)) { /* need malloc space */
+ allocbufa=(decNumber *)malloc(needbytes);
+ if (allocbufa==NULL) { /* hopeless -- abandon */
+ status|=DEC_Insufficient_storage;
+ break;}
+ acc=allocbufa; /* use the allocated space */
+ }
+ /* multiply with extended range and necessary precision */
+ /*printf("emin=%ld\n", dcmul.emin); */
+ decMultiplyOp(acc, lhs, rhs, &dcmul, &status);
+ /* Only Invalid operation (from sNaN or Inf * 0) is possible in */
+ /* status; if either is seen than ignore fhs (in case it is */
+ /* another sNaN) and set acc to NaN unless we had an sNaN */
+ /* [decMultiplyOp leaves that to caller] */
+ /* Note sNaN has to go through addOp to shorten payload if */
+ /* necessary */
+ if ((status&DEC_Invalid_operation)!=0) {
+ if (!(status&DEC_sNaN)) { /* but be true invalid */
+ uprv_decNumberZero(res); /* acc not yet set */
+ res->bits=DECNAN;
+ break;
+ }
+ uprv_decNumberZero(&dzero); /* make 0 (any non-NaN would do) */
+ fhs=&dzero; /* use that */
+ }
+ #if DECCHECK
+ else { /* multiply was OK */
+ if (status!=0) printf("Status=%08lx after FMA multiply\n", (LI)status);
+ }
+ #endif
+ /* add the third operand and result -> res, and all is done */
+ decAddOp(res, acc, fhs, set, 0, &status);
+ } while(0); /* end protected */
+
+ if (allocbufa!=NULL) free(allocbufa); /* drop any storage used */
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberFMA */
+
+/* ------------------------------------------------------------------ */
+/* decNumberInvert -- invert a Number, digitwise */
+/* */
+/* This computes C = ~A */
+/* */
+/* res is C, the result. C may be A (e.g., X=~X) */
+/* rhs is A */
+/* set is the context (used for result length and error report) */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* Logical function restrictions apply (see above); a NaN is */
+/* returned with Invalid_operation if a restriction is violated. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberInvert(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ const Unit *ua, *msua; /* -> operand and its msu */
+ Unit *uc, *msuc; /* -> result and its msu */
+ Int msudigs; /* digits in res msu */
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ if (rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) {
+ decStatus(res, DEC_Invalid_operation, set);
+ return res;
+ }
+ /* operand is valid */
+ ua=rhs->lsu; /* bottom-up */
+ uc=res->lsu; /* .. */
+ msua=ua+D2U(rhs->digits)-1; /* -> msu of rhs */
+ msuc=uc+D2U(set->digits)-1; /* -> msu of result */
+ msudigs=MSUDIGITS(set->digits); /* [faster than remainder] */
+ for (; uc<=msuc; ua++, uc++) { /* Unit loop */
+ Unit a; /* extract unit */
+ Int i, j; /* work */
+ if (ua>msua) a=0;
+ else a=*ua;
+ *uc=0; /* can now write back */
+ /* always need to examine all bits in rhs */
+ /* This loop could be unrolled and/or use BIN2BCD tables */
+ for (i=0; i<DECDPUN; i++) {
+ if ((~a)&1) *uc=*uc+(Unit)powers[i]; /* effect INVERT */
+ j=a%10;
+ a=a/10;
+ if (j>1) {
+ decStatus(res, DEC_Invalid_operation, set);
+ return res;
+ }
+ if (uc==msuc && i==msudigs-1) break; /* just did final digit */
+ } /* each digit */
+ } /* each unit */
+ /* [here uc-1 is the msu of the result] */
+ res->digits=decGetDigits(res->lsu, static_cast<int32_t>(uc - res->lsu));
+ res->exponent=0; /* integer */
+ res->bits=0; /* sign=0 */
+ return res; /* [no status to set] */
+ } /* decNumberInvert */
+
+/* ------------------------------------------------------------------ */
+/* decNumberLn -- natural logarithm */
+/* */
+/* This computes C = ln(A) */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context; note that rounding mode has no effect */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* Notable cases: */
+/* A<0 -> Invalid */
+/* A=0 -> -Infinity (Exact) */
+/* A=+Infinity -> +Infinity (Exact) */
+/* A=1 exactly -> 0 (Exact) */
+/* */
+/* Mathematical function restrictions apply (see above); a NaN is */
+/* returned with Invalid_operation if a restriction is violated. */
+/* */
+/* An Inexact result is rounded using DEC_ROUND_HALF_EVEN; it will */
+/* almost always be correctly rounded, but may be up to 1 ulp in */
+/* error in rare cases. */
+/* ------------------------------------------------------------------ */
+/* This is a wrapper for decLnOp which can handle the slightly wider */
+/* (+11) range needed by Ln, Log10, etc. (which may have to be able */
+/* to calculate at p+e+2). */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberLn(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ uInt status=0; /* accumulator */
+ #if DECSUBSET
+ decNumber *allocrhs=NULL; /* non-NULL if rounded rhs allocated */
+ #endif
+
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ /* Check restrictions; this is a math function; if not violated */
+ /* then carry out the operation. */
+ if (!decCheckMath(rhs, set, &status)) do { /* protect allocation */
+ #if DECSUBSET
+ if (!set->extended) {
+ /* reduce operand and set lostDigits status, as needed */
+ if (rhs->digits>set->digits) {
+ allocrhs=decRoundOperand(rhs, set, &status);
+ if (allocrhs==NULL) break;
+ rhs=allocrhs;
+ }
+ /* special check in subset for rhs=0 */
+ if (ISZERO(rhs)) { /* +/- zeros -> error */
+ status|=DEC_Invalid_operation;
+ break;}
+ } /* extended=0 */
+ #endif
+ decLnOp(res, rhs, set, &status);
+ } while(0); /* end protected */
+
+ #if DECSUBSET
+ if (allocrhs !=NULL) free(allocrhs); /* drop any storage used */
+ #endif
+ /* apply significant status */
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberLn */
+
+/* ------------------------------------------------------------------ */
+/* decNumberLogB - get adjusted exponent, by 754 rules */
+/* */
+/* This computes C = adjustedexponent(A) */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context, used only for digits and status */
+/* */
+/* C must have space for 10 digits (A might have 10**9 digits and */
+/* an exponent of +999999999, or one digit and an exponent of */
+/* -1999999999). */
+/* */
+/* This returns the adjusted exponent of A after (in theory) padding */
+/* with zeros on the right to set->digits digits while keeping the */
+/* same value. The exponent is not limited by emin/emax. */
+/* */
+/* Notable cases: */
+/* A<0 -> Use |A| */
+/* A=0 -> -Infinity (Division by zero) */
+/* A=Infinite -> +Infinity (Exact) */
+/* A=1 exactly -> 0 (Exact) */
+/* NaNs are propagated as usual */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberLogB(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ uInt status=0; /* accumulator */
+
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ /* NaNs as usual; Infinities return +Infinity; 0->oops */
+ if (decNumberIsNaN(rhs)) decNaNs(res, rhs, NULL, set, &status);
+ else if (decNumberIsInfinite(rhs)) uprv_decNumberCopyAbs(res, rhs);
+ else if (decNumberIsZero(rhs)) {
+ uprv_decNumberZero(res); /* prepare for Infinity */
+ res->bits=DECNEG|DECINF; /* -Infinity */
+ status|=DEC_Division_by_zero; /* as per 754 */
+ }
+ else { /* finite non-zero */
+ Int ae=rhs->exponent+rhs->digits-1; /* adjusted exponent */
+ uprv_decNumberFromInt32(res, ae); /* lay it out */
+ }
+
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberLogB */
+
+/* ------------------------------------------------------------------ */
+/* decNumberLog10 -- logarithm in base 10 */
+/* */
+/* This computes C = log10(A) */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context; note that rounding mode has no effect */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* Notable cases: */
+/* A<0 -> Invalid */
+/* A=0 -> -Infinity (Exact) */
+/* A=+Infinity -> +Infinity (Exact) */
+/* A=10**n (if n is an integer) -> n (Exact) */
+/* */
+/* Mathematical function restrictions apply (see above); a NaN is */
+/* returned with Invalid_operation if a restriction is violated. */
+/* */
+/* An Inexact result is rounded using DEC_ROUND_HALF_EVEN; it will */
+/* almost always be correctly rounded, but may be up to 1 ulp in */
+/* error in rare cases. */
+/* ------------------------------------------------------------------ */
+/* This calculates ln(A)/ln(10) using appropriate precision. For */
+/* ln(A) this is the max(p, rhs->digits + t) + 3, where p is the */
+/* requested digits and t is the number of digits in the exponent */
+/* (maximum 6). For ln(10) it is p + 3; this is often handled by the */
+/* fastpath in decLnOp. The final division is done to the requested */
+/* precision. */
+/* ------------------------------------------------------------------ */
+#if defined(__clang__) || U_GCC_MAJOR_MINOR >= 406
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
+#endif
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberLog10(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ uInt status=0, ignore=0; /* status accumulators */
+ uInt needbytes; /* for space calculations */
+ Int p; /* working precision */
+ Int t; /* digits in exponent of A */
+
+ /* buffers for a and b working decimals */
+ /* (adjustment calculator, same size) */
+ decNumber bufa[D2N(DECBUFFER+2)];
+ decNumber *allocbufa=NULL; /* -> allocated bufa, iff allocated */
+ decNumber *a=bufa; /* temporary a */
+ decNumber bufb[D2N(DECBUFFER+2)];
+ decNumber *allocbufb=NULL; /* -> allocated bufb, iff allocated */
+ decNumber *b=bufb; /* temporary b */
+ decNumber bufw[D2N(10)]; /* working 2-10 digit number */
+ decNumber *w=bufw; /* .. */
+ #if DECSUBSET
+ decNumber *allocrhs=NULL; /* non-NULL if rounded rhs allocated */
+ #endif
+
+ decContext aset; /* working context */
+
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ /* Check restrictions; this is a math function; if not violated */
+ /* then carry out the operation. */
+ if (!decCheckMath(rhs, set, &status)) do { /* protect malloc */
+ #if DECSUBSET
+ if (!set->extended) {
+ /* reduce operand and set lostDigits status, as needed */
+ if (rhs->digits>set->digits) {
+ allocrhs=decRoundOperand(rhs, set, &status);
+ if (allocrhs==NULL) break;
+ rhs=allocrhs;
+ }
+ /* special check in subset for rhs=0 */
+ if (ISZERO(rhs)) { /* +/- zeros -> error */
+ status|=DEC_Invalid_operation;
+ break;}
+ } /* extended=0 */
+ #endif
+
+ uprv_decContextDefault(&aset, DEC_INIT_DECIMAL64); /* clean context */
+
+ /* handle exact powers of 10; only check if +ve finite */
+ if (!(rhs->bits&(DECNEG|DECSPECIAL)) && !ISZERO(rhs)) {
+ Int residue=0; /* (no residue) */
+ uInt copystat=0; /* clean status */
+
+ /* round to a single digit... */
+ aset.digits=1;
+ decCopyFit(w, rhs, &aset, &residue, &copystat); /* copy & shorten */
+ /* if exact and the digit is 1, rhs is a power of 10 */
+ if (!(copystat&DEC_Inexact) && w->lsu[0]==1) {
+ /* the exponent, conveniently, is the power of 10; making */
+ /* this the result needs a little care as it might not fit, */
+ /* so first convert it into the working number, and then move */
+ /* to res */
+ uprv_decNumberFromInt32(w, w->exponent);
+ residue=0;
+ decCopyFit(res, w, set, &residue, &status); /* copy & round */
+ decFinish(res, set, &residue, &status); /* cleanup/set flags */
+ break;
+ } /* not a power of 10 */
+ } /* not a candidate for exact */
+
+ /* simplify the information-content calculation to use 'total */
+ /* number of digits in a, including exponent' as compared to the */
+ /* requested digits, as increasing this will only rarely cost an */
+ /* iteration in ln(a) anyway */
+ t=6; /* it can never be >6 */
+
+ /* allocate space when needed... */
+ p=(rhs->digits+t>set->digits?rhs->digits+t:set->digits)+3;
+ needbytes=sizeof(decNumber)+(D2U(p)-1)*sizeof(Unit);
+ if (needbytes>sizeof(bufa)) { /* need malloc space */
+ allocbufa=(decNumber *)malloc(needbytes);
+ if (allocbufa==NULL) { /* hopeless -- abandon */
+ status|=DEC_Insufficient_storage;
+ break;}
+ a=allocbufa; /* use the allocated space */
+ }
+ aset.digits=p; /* as calculated */
+ aset.emax=DEC_MAX_MATH; /* usual bounds */
+ aset.emin=-DEC_MAX_MATH; /* .. */
+ aset.clamp=0; /* and no concrete format */
+ decLnOp(a, rhs, &aset, &status); /* a=ln(rhs) */
+
+ /* skip the division if the result so far is infinite, NaN, or */
+ /* zero, or there was an error; note NaN from sNaN needs copy */
+ if (status&DEC_NaNs && !(status&DEC_sNaN)) break;
+ if (a->bits&DECSPECIAL || ISZERO(a)) {
+ uprv_decNumberCopy(res, a); /* [will fit] */
+ break;}
+
+ /* for ln(10) an extra 3 digits of precision are needed */
+ p=set->digits+3;
+ needbytes=sizeof(decNumber)+(D2U(p)-1)*sizeof(Unit);
+ if (needbytes>sizeof(bufb)) { /* need malloc space */
+ allocbufb=(decNumber *)malloc(needbytes);
+ if (allocbufb==NULL) { /* hopeless -- abandon */
+ status|=DEC_Insufficient_storage;
+ break;}
+ b=allocbufb; /* use the allocated space */
+ }
+ uprv_decNumberZero(w); /* set up 10... */
+ #if DECDPUN==1
+ w->lsu[1]=1; w->lsu[0]=0; /* .. */
+ #else
+ w->lsu[0]=10; /* .. */
+ #endif
+ w->digits=2; /* .. */
+
+ aset.digits=p;
+ decLnOp(b, w, &aset, &ignore); /* b=ln(10) */
+
+ aset.digits=set->digits; /* for final divide */
+ decDivideOp(res, a, b, &aset, DIVIDE, &status); /* into result */
+ } while(0); /* [for break] */
+
+ if (allocbufa!=NULL) free(allocbufa); /* drop any storage used */
+ if (allocbufb!=NULL) free(allocbufb); /* .. */
+ #if DECSUBSET
+ if (allocrhs !=NULL) free(allocrhs); /* .. */
+ #endif
+ /* apply significant status */
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberLog10 */
+#if defined(__clang__) || U_GCC_MAJOR_MINOR >= 406
+#pragma GCC diagnostic pop
+#endif
+
+/* ------------------------------------------------------------------ */
+/* decNumberMax -- compare two Numbers and return the maximum */
+/* */
+/* This computes C = A ? B, returning the maximum by 754 rules */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberMax(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decCompareOp(res, lhs, rhs, set, COMPMAX, &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberMax */
+
+/* ------------------------------------------------------------------ */
+/* decNumberMaxMag -- compare and return the maximum by magnitude */
+/* */
+/* This computes C = A ? B, returning the maximum by 754 rules */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberMaxMag(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decCompareOp(res, lhs, rhs, set, COMPMAXMAG, &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberMaxMag */
+
+/* ------------------------------------------------------------------ */
+/* decNumberMin -- compare two Numbers and return the minimum */
+/* */
+/* This computes C = A ? B, returning the minimum by 754 rules */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberMin(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decCompareOp(res, lhs, rhs, set, COMPMIN, &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberMin */
+
+/* ------------------------------------------------------------------ */
+/* decNumberMinMag -- compare and return the minimum by magnitude */
+/* */
+/* This computes C = A ? B, returning the minimum by 754 rules */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberMinMag(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decCompareOp(res, lhs, rhs, set, COMPMINMAG, &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberMinMag */
+
+/* ------------------------------------------------------------------ */
+/* decNumberMinus -- prefix minus operator */
+/* */
+/* This computes C = 0 - A */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context */
+/* */
+/* See also decNumberCopyNegate for a quiet bitwise version of this. */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+/* Simply use AddOp for the subtract, which will do the necessary. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberMinus(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ decNumber dzero;
+ uInt status=0; /* accumulator */
+
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ uprv_decNumberZero(&dzero); /* make 0 */
+ dzero.exponent=rhs->exponent; /* [no coefficient expansion] */
+ decAddOp(res, &dzero, rhs, set, DECNEG, &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberMinus */
+
+/* ------------------------------------------------------------------ */
+/* decNumberNextMinus -- next towards -Infinity */
+/* */
+/* This computes C = A - infinitesimal, rounded towards -Infinity */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context */
+/* */
+/* This is a generalization of 754 NextDown. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberNextMinus(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ decNumber dtiny; /* constant */
+ decContext workset=*set; /* work */
+ uInt status=0; /* accumulator */
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ /* +Infinity is the special case */
+ if ((rhs->bits&(DECINF|DECNEG))==DECINF) {
+ decSetMaxValue(res, set); /* is +ve */
+ /* there is no status to set */
+ return res;
+ }
+ uprv_decNumberZero(&dtiny); /* start with 0 */
+ dtiny.lsu[0]=1; /* make number that is .. */
+ dtiny.exponent=DEC_MIN_EMIN-1; /* .. smaller than tiniest */
+ workset.round=DEC_ROUND_FLOOR;
+ decAddOp(res, rhs, &dtiny, &workset, DECNEG, &status);
+ status&=DEC_Invalid_operation|DEC_sNaN; /* only sNaN Invalid please */
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberNextMinus */
+
+/* ------------------------------------------------------------------ */
+/* decNumberNextPlus -- next towards +Infinity */
+/* */
+/* This computes C = A + infinitesimal, rounded towards +Infinity */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context */
+/* */
+/* This is a generalization of 754 NextUp. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberNextPlus(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ decNumber dtiny; /* constant */
+ decContext workset=*set; /* work */
+ uInt status=0; /* accumulator */
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ /* -Infinity is the special case */
+ if ((rhs->bits&(DECINF|DECNEG))==(DECINF|DECNEG)) {
+ decSetMaxValue(res, set);
+ res->bits=DECNEG; /* negative */
+ /* there is no status to set */
+ return res;
+ }
+ uprv_decNumberZero(&dtiny); /* start with 0 */
+ dtiny.lsu[0]=1; /* make number that is .. */
+ dtiny.exponent=DEC_MIN_EMIN-1; /* .. smaller than tiniest */
+ workset.round=DEC_ROUND_CEILING;
+ decAddOp(res, rhs, &dtiny, &workset, 0, &status);
+ status&=DEC_Invalid_operation|DEC_sNaN; /* only sNaN Invalid please */
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberNextPlus */
+
+/* ------------------------------------------------------------------ */
+/* decNumberNextToward -- next towards rhs */
+/* */
+/* This computes C = A +/- infinitesimal, rounded towards */
+/* +/-Infinity in the direction of B, as per 754-1985 nextafter */
+/* modified during revision but dropped from 754-2008. */
+/* */
+/* res is C, the result. C may be A or B. */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* This is a generalization of 754-1985 NextAfter. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberNextToward(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ decNumber dtiny; /* constant */
+ decContext workset=*set; /* work */
+ Int result; /* .. */
+ uInt status=0; /* accumulator */
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs)) {
+ decNaNs(res, lhs, rhs, set, &status);
+ }
+ else { /* Is numeric, so no chance of sNaN Invalid, etc. */
+ result=decCompare(lhs, rhs, 0); /* sign matters */
+ if (result==BADINT) status|=DEC_Insufficient_storage; /* rare */
+ else { /* valid compare */
+ if (result==0) uprv_decNumberCopySign(res, lhs, rhs); /* easy */
+ else { /* differ: need NextPlus or NextMinus */
+ uByte sub; /* add or subtract */
+ if (result<0) { /* lhs<rhs, do nextplus */
+ /* -Infinity is the special case */
+ if ((lhs->bits&(DECINF|DECNEG))==(DECINF|DECNEG)) {
+ decSetMaxValue(res, set);
+ res->bits=DECNEG; /* negative */
+ return res; /* there is no status to set */
+ }
+ workset.round=DEC_ROUND_CEILING;
+ sub=0; /* add, please */
+ } /* plus */
+ else { /* lhs>rhs, do nextminus */
+ /* +Infinity is the special case */
+ if ((lhs->bits&(DECINF|DECNEG))==DECINF) {
+ decSetMaxValue(res, set);
+ return res; /* there is no status to set */
+ }
+ workset.round=DEC_ROUND_FLOOR;
+ sub=DECNEG; /* subtract, please */
+ } /* minus */
+ uprv_decNumberZero(&dtiny); /* start with 0 */
+ dtiny.lsu[0]=1; /* make number that is .. */
+ dtiny.exponent=DEC_MIN_EMIN-1; /* .. smaller than tiniest */
+ decAddOp(res, lhs, &dtiny, &workset, sub, &status); /* + or - */
+ /* turn off exceptions if the result is a normal number */
+ /* (including Nmin), otherwise let all status through */
+ if (uprv_decNumberIsNormal(res, set)) status=0;
+ } /* unequal */
+ } /* compare OK */
+ } /* numeric */
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberNextToward */
+
+/* ------------------------------------------------------------------ */
+/* decNumberOr -- OR two Numbers, digitwise */
+/* */
+/* This computes C = A | B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X|X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context (used for result length and error report) */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* Logical function restrictions apply (see above); a NaN is */
+/* returned with Invalid_operation if a restriction is violated. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberOr(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ const Unit *ua, *ub; /* -> operands */
+ const Unit *msua, *msub; /* -> operand msus */
+ Unit *uc, *msuc; /* -> result and its msu */
+ Int msudigs; /* digits in res msu */
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ if (lhs->exponent!=0 || decNumberIsSpecial(lhs) || decNumberIsNegative(lhs)
+ || rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) {
+ decStatus(res, DEC_Invalid_operation, set);
+ return res;
+ }
+ /* operands are valid */
+ ua=lhs->lsu; /* bottom-up */
+ ub=rhs->lsu; /* .. */
+ uc=res->lsu; /* .. */
+ msua=ua+D2U(lhs->digits)-1; /* -> msu of lhs */
+ msub=ub+D2U(rhs->digits)-1; /* -> msu of rhs */
+ msuc=uc+D2U(set->digits)-1; /* -> msu of result */
+ msudigs=MSUDIGITS(set->digits); /* [faster than remainder] */
+ for (; uc<=msuc; ua++, ub++, uc++) { /* Unit loop */
+ Unit a, b; /* extract units */
+ if (ua>msua) a=0;
+ else a=*ua;
+ if (ub>msub) b=0;
+ else b=*ub;
+ *uc=0; /* can now write back */
+ if (a|b) { /* maybe 1 bits to examine */
+ Int i, j;
+ /* This loop could be unrolled and/or use BIN2BCD tables */
+ for (i=0; i<DECDPUN; i++) {
+ if ((a|b)&1) *uc=*uc+(Unit)powers[i]; /* effect OR */
+ j=a%10;
+ a=a/10;
+ j|=b%10;
+ b=b/10;
+ if (j>1) {
+ decStatus(res, DEC_Invalid_operation, set);
+ return res;
+ }
+ if (uc==msuc && i==msudigs-1) break; /* just did final digit */
+ } /* each digit */
+ } /* non-zero */
+ } /* each unit */
+ /* [here uc-1 is the msu of the result] */
+ res->digits=decGetDigits(res->lsu, static_cast<int32_t>(uc-res->lsu));
+ res->exponent=0; /* integer */
+ res->bits=0; /* sign=0 */
+ return res; /* [no status to set] */
+ } /* decNumberOr */
+
+/* ------------------------------------------------------------------ */
+/* decNumberPlus -- prefix plus operator */
+/* */
+/* This computes C = 0 + A */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context */
+/* */
+/* See also decNumberCopy for a quiet bitwise version of this. */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+/* This simply uses AddOp; Add will take fast path after preparing A. */
+/* Performance is a concern here, as this routine is often used to */
+/* check operands and apply rounding and overflow/underflow testing. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberPlus(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ decNumber dzero;
+ uInt status=0; /* accumulator */
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ uprv_decNumberZero(&dzero); /* make 0 */
+ dzero.exponent=rhs->exponent; /* [no coefficient expansion] */
+ decAddOp(res, &dzero, rhs, set, 0, &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberPlus */
+
+/* ------------------------------------------------------------------ */
+/* decNumberMultiply -- multiply two Numbers */
+/* */
+/* This computes C = A x B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X+X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberMultiply(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decMultiplyOp(res, lhs, rhs, set, &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberMultiply */
+
+/* ------------------------------------------------------------------ */
+/* decNumberPower -- raise a number to a power */
+/* */
+/* This computes C = A ** B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X**X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* Mathematical function restrictions apply (see above); a NaN is */
+/* returned with Invalid_operation if a restriction is violated. */
+/* */
+/* However, if 1999999997<=B<=999999999 and B is an integer then the */
+/* restrictions on A and the context are relaxed to the usual bounds, */
+/* for compatibility with the earlier (integer power only) version */
+/* of this function. */
+/* */
+/* When B is an integer, the result may be exact, even if rounded. */
+/* */
+/* The final result is rounded according to the context; it will */
+/* almost always be correctly rounded, but may be up to 1 ulp in */
+/* error in rare cases. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberPower(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ #if DECSUBSET
+ decNumber *alloclhs=NULL; /* non-NULL if rounded lhs allocated */
+ decNumber *allocrhs=NULL; /* .., rhs */
+ #endif
+ decNumber *allocdac=NULL; /* -> allocated acc buffer, iff used */
+ decNumber *allocinv=NULL; /* -> allocated 1/x buffer, iff used */
+ Int reqdigits=set->digits; /* requested DIGITS */
+ Int n; /* rhs in binary */
+ Flag rhsint=0; /* 1 if rhs is an integer */
+ Flag useint=0; /* 1 if can use integer calculation */
+ Flag isoddint=0; /* 1 if rhs is an integer and odd */
+ Int i; /* work */
+ #if DECSUBSET
+ Int dropped; /* .. */
+ #endif
+ uInt needbytes; /* buffer size needed */
+ Flag seenbit; /* seen a bit while powering */
+ Int residue=0; /* rounding residue */
+ uInt status=0; /* accumulators */
+ uByte bits=0; /* result sign if errors */
+ decContext aset; /* working context */
+ decNumber dnOne; /* work value 1... */
+ /* local accumulator buffer [a decNumber, with digits+elength+1 digits] */
+ decNumber dacbuff[D2N(DECBUFFER+9)];
+ decNumber *dac=dacbuff; /* -> result accumulator */
+ /* same again for possible 1/lhs calculation */
+ decNumber invbuff[D2N(DECBUFFER+9)];
+
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ do { /* protect allocated storage */
+ #if DECSUBSET
+ if (!set->extended) { /* reduce operands and set status, as needed */
+ if (lhs->digits>reqdigits) {
+ alloclhs=decRoundOperand(lhs, set, &status);
+ if (alloclhs==NULL) break;
+ lhs=alloclhs;
+ }
+ if (rhs->digits>reqdigits) {
+ allocrhs=decRoundOperand(rhs, set, &status);
+ if (allocrhs==NULL) break;
+ rhs=allocrhs;
+ }
+ }
+ #endif
+ /* [following code does not require input rounding] */
+
+ /* handle NaNs and rhs Infinity (lhs infinity is harder) */
+ if (SPECIALARGS) {
+ if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs)) { /* NaNs */
+ decNaNs(res, lhs, rhs, set, &status);
+ break;}
+ if (decNumberIsInfinite(rhs)) { /* rhs Infinity */
+ Flag rhsneg=rhs->bits&DECNEG; /* save rhs sign */
+ if (decNumberIsNegative(lhs) /* lhs<0 */
+ && !decNumberIsZero(lhs)) /* .. */
+ status|=DEC_Invalid_operation;
+ else { /* lhs >=0 */
+ uprv_decNumberZero(&dnOne); /* set up 1 */
+ dnOne.lsu[0]=1;
+ uprv_decNumberCompare(dac, lhs, &dnOne, set); /* lhs ? 1 */
+ uprv_decNumberZero(res); /* prepare for 0/1/Infinity */
+ if (decNumberIsNegative(dac)) { /* lhs<1 */
+ if (rhsneg) res->bits|=DECINF; /* +Infinity [else is +0] */
+ }
+ else if (dac->lsu[0]==0) { /* lhs=1 */
+ /* 1**Infinity is inexact, so return fully-padded 1.0000 */
+ Int shift=set->digits-1;
+ *res->lsu=1; /* was 0, make int 1 */
+ res->digits=decShiftToMost(res->lsu, 1, shift);
+ res->exponent=-shift; /* make 1.0000... */
+ status|=DEC_Inexact|DEC_Rounded; /* deemed inexact */
+ }
+ else { /* lhs>1 */
+ if (!rhsneg) res->bits|=DECINF; /* +Infinity [else is +0] */
+ }
+ } /* lhs>=0 */
+ break;}
+ /* [lhs infinity drops through] */
+ } /* specials */
+
+ /* Original rhs may be an integer that fits and is in range */
+ n=decGetInt(rhs);
+ if (n!=BADINT) { /* it is an integer */
+ rhsint=1; /* record the fact for 1**n */
+ isoddint=(Flag)n&1; /* [works even if big] */
+ if (n!=BIGEVEN && n!=BIGODD) /* can use integer path? */
+ useint=1; /* looks good */
+ }
+
+ if (decNumberIsNegative(lhs) /* -x .. */
+ && isoddint) bits=DECNEG; /* .. to an odd power */
+
+ /* handle LHS infinity */
+ if (decNumberIsInfinite(lhs)) { /* [NaNs already handled] */
+ uByte rbits=rhs->bits; /* save */
+ uprv_decNumberZero(res); /* prepare */
+ if (n==0) *res->lsu=1; /* [-]Inf**0 => 1 */
+ else {
+ /* -Inf**nonint -> error */
+ if (!rhsint && decNumberIsNegative(lhs)) {
+ status|=DEC_Invalid_operation; /* -Inf**nonint is error */
+ break;}
+ if (!(rbits & DECNEG)) bits|=DECINF; /* was not a **-n */
+ /* [otherwise will be 0 or -0] */
+ res->bits=bits;
+ }
+ break;}
+
+ /* similarly handle LHS zero */
+ if (decNumberIsZero(lhs)) {
+ if (n==0) { /* 0**0 => Error */
+ #if DECSUBSET
+ if (!set->extended) { /* [unless subset] */
+ uprv_decNumberZero(res);
+ *res->lsu=1; /* return 1 */
+ break;}
+ #endif
+ status|=DEC_Invalid_operation;
+ }
+ else { /* 0**x */
+ uByte rbits=rhs->bits; /* save */
+ if (rbits & DECNEG) { /* was a 0**(-n) */
+ #if DECSUBSET
+ if (!set->extended) { /* [bad if subset] */
+ status|=DEC_Invalid_operation;
+ break;}
+ #endif
+ bits|=DECINF;
+ }
+ uprv_decNumberZero(res); /* prepare */
+ /* [otherwise will be 0 or -0] */
+ res->bits=bits;
+ }
+ break;}
+
+ /* here both lhs and rhs are finite; rhs==0 is handled in the */
+ /* integer path. Next handle the non-integer cases */
+ if (!useint) { /* non-integral rhs */
+ /* any -ve lhs is bad, as is either operand or context out of */
+ /* bounds */
+ if (decNumberIsNegative(lhs)) {
+ status|=DEC_Invalid_operation;
+ break;}
+ if (decCheckMath(lhs, set, &status)
+ || decCheckMath(rhs, set, &status)) break; /* variable status */
+
+ uprv_decContextDefault(&aset, DEC_INIT_DECIMAL64); /* clean context */
+ aset.emax=DEC_MAX_MATH; /* usual bounds */
+ aset.emin=-DEC_MAX_MATH; /* .. */
+ aset.clamp=0; /* and no concrete format */
+
+ /* calculate the result using exp(ln(lhs)*rhs), which can */
+ /* all be done into the accumulator, dac. The precision needed */
+ /* is enough to contain the full information in the lhs (which */
+ /* is the total digits, including exponent), or the requested */
+ /* precision, if larger, + 4; 6 is used for the exponent */
+ /* maximum length, and this is also used when it is shorter */
+ /* than the requested digits as it greatly reduces the >0.5 ulp */
+ /* cases at little cost (because Ln doubles digits each */
+ /* iteration so a few extra digits rarely causes an extra */
+ /* iteration) */
+ aset.digits=MAXI(lhs->digits, set->digits)+6+4;
+ } /* non-integer rhs */
+
+ else { /* rhs is in-range integer */
+ if (n==0) { /* x**0 = 1 */
+ /* (0**0 was handled above) */
+ uprv_decNumberZero(res); /* result=1 */
+ *res->lsu=1; /* .. */
+ break;}
+ /* rhs is a non-zero integer */
+ if (n<0) n=-n; /* use abs(n) */
+
+ aset=*set; /* clone the context */
+ aset.round=DEC_ROUND_HALF_EVEN; /* internally use balanced */
+ /* calculate the working DIGITS */
+ aset.digits=reqdigits+(rhs->digits+rhs->exponent)+2;
+ #if DECSUBSET
+ if (!set->extended) aset.digits--; /* use classic precision */
+ #endif
+ /* it's an error if this is more than can be handled */
+ if (aset.digits>DECNUMMAXP) {status|=DEC_Invalid_operation; break;}
+ } /* integer path */
+
+ /* aset.digits is the count of digits for the accumulator needed */
+ /* if accumulator is too long for local storage, then allocate */
+ needbytes=sizeof(decNumber)+(D2U(aset.digits)-1)*sizeof(Unit);
+ /* [needbytes also used below if 1/lhs needed] */
+ if (needbytes>sizeof(dacbuff)) {
+ allocdac=(decNumber *)malloc(needbytes);
+ if (allocdac==NULL) { /* hopeless -- abandon */
+ status|=DEC_Insufficient_storage;
+ break;}
+ dac=allocdac; /* use the allocated space */
+ }
+ /* here, aset is set up and accumulator is ready for use */
+
+ if (!useint) { /* non-integral rhs */
+ /* x ** y; special-case x=1 here as it will otherwise always */
+ /* reduce to integer 1; decLnOp has a fastpath which detects */
+ /* the case of x=1 */
+ decLnOp(dac, lhs, &aset, &status); /* dac=ln(lhs) */
+ /* [no error possible, as lhs 0 already handled] */
+ if (ISZERO(dac)) { /* x==1, 1.0, etc. */
+ /* need to return fully-padded 1.0000 etc., but rhsint->1 */
+ *dac->lsu=1; /* was 0, make int 1 */
+ if (!rhsint) { /* add padding */
+ Int shift=set->digits-1;
+ dac->digits=decShiftToMost(dac->lsu, 1, shift);
+ dac->exponent=-shift; /* make 1.0000... */
+ status|=DEC_Inexact|DEC_Rounded; /* deemed inexact */
+ }
+ }
+ else {
+ decMultiplyOp(dac, dac, rhs, &aset, &status); /* dac=dac*rhs */
+ decExpOp(dac, dac, &aset, &status); /* dac=exp(dac) */
+ }
+ /* and drop through for final rounding */
+ } /* non-integer rhs */
+
+ else { /* carry on with integer */
+ uprv_decNumberZero(dac); /* acc=1 */
+ *dac->lsu=1; /* .. */
+
+ /* if a negative power the constant 1 is needed, and if not subset */
+ /* invert the lhs now rather than inverting the result later */
+ if (decNumberIsNegative(rhs)) { /* was a **-n [hence digits>0] */
+ decNumber *inv=invbuff; /* asssume use fixed buffer */
+ uprv_decNumberCopy(&dnOne, dac); /* dnOne=1; [needed now or later] */
+ #if DECSUBSET
+ if (set->extended) { /* need to calculate 1/lhs */
+ #endif
+ /* divide lhs into 1, putting result in dac [dac=1/dac] */
+ decDivideOp(dac, &dnOne, lhs, &aset, DIVIDE, &status);
+ /* now locate or allocate space for the inverted lhs */
+ if (needbytes>sizeof(invbuff)) {
+ allocinv=(decNumber *)malloc(needbytes);
+ if (allocinv==NULL) { /* hopeless -- abandon */
+ status|=DEC_Insufficient_storage;
+ break;}
+ inv=allocinv; /* use the allocated space */
+ }
+ /* [inv now points to big-enough buffer or allocated storage] */
+ uprv_decNumberCopy(inv, dac); /* copy the 1/lhs */
+ uprv_decNumberCopy(dac, &dnOne); /* restore acc=1 */
+ lhs=inv; /* .. and go forward with new lhs */
+ #if DECSUBSET
+ }
+ #endif
+ }
+
+ /* Raise-to-the-power loop... */
+ seenbit=0; /* set once a 1-bit is encountered */
+ for (i=1;;i++){ /* for each bit [top bit ignored] */
+ /* abandon if had overflow or terminal underflow */
+ if (status & (DEC_Overflow|DEC_Underflow)) { /* interesting? */
+ if (status&DEC_Overflow || ISZERO(dac)) break;
+ }
+ /* [the following two lines revealed an optimizer bug in a C++ */
+ /* compiler, with symptom: 5**3 -> 25, when n=n+n was used] */
+ n=n<<1; /* move next bit to testable position */
+ if (n<0) { /* top bit is set */
+ seenbit=1; /* OK, significant bit seen */
+ decMultiplyOp(dac, dac, lhs, &aset, &status); /* dac=dac*x */
+ }
+ if (i==31) break; /* that was the last bit */
+ if (!seenbit) continue; /* no need to square 1 */
+ decMultiplyOp(dac, dac, dac, &aset, &status); /* dac=dac*dac [square] */
+ } /*i*/ /* 32 bits */
+
+ /* complete internal overflow or underflow processing */
+ if (status & (DEC_Overflow|DEC_Underflow)) {
+ #if DECSUBSET
+ /* If subset, and power was negative, reverse the kind of -erflow */
+ /* [1/x not yet done] */
+ if (!set->extended && decNumberIsNegative(rhs)) {
+ if (status & DEC_Overflow)
+ status^=DEC_Overflow | DEC_Underflow | DEC_Subnormal;
+ else { /* trickier -- Underflow may or may not be set */
+ status&=~(DEC_Underflow | DEC_Subnormal); /* [one or both] */
+ status|=DEC_Overflow;
+ }
+ }
+ #endif
+ dac->bits=(dac->bits & ~DECNEG) | bits; /* force correct sign */
+ /* round subnormals [to set.digits rather than aset.digits] */
+ /* or set overflow result similarly as required */
+ decFinalize(dac, set, &residue, &status);
+ uprv_decNumberCopy(res, dac); /* copy to result (is now OK length) */
+ break;
+ }
+
+ #if DECSUBSET
+ if (!set->extended && /* subset math */
+ decNumberIsNegative(rhs)) { /* was a **-n [hence digits>0] */
+ /* so divide result into 1 [dac=1/dac] */
+ decDivideOp(dac, &dnOne, dac, &aset, DIVIDE, &status);
+ }
+ #endif
+ } /* rhs integer path */
+
+ /* reduce result to the requested length and copy to result */
+ decCopyFit(res, dac, set, &residue, &status);
+ decFinish(res, set, &residue, &status); /* final cleanup */
+ #if DECSUBSET
+ if (!set->extended) decTrim(res, set, 0, 1, &dropped); /* trailing zeros */
+ #endif
+ } while(0); /* end protected */
+
+ if (allocdac!=NULL) free(allocdac); /* drop any storage used */
+ if (allocinv!=NULL) free(allocinv); /* .. */
+ #if DECSUBSET
+ if (alloclhs!=NULL) free(alloclhs); /* .. */
+ if (allocrhs!=NULL) free(allocrhs); /* .. */
+ #endif
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberPower */
+
+/* ------------------------------------------------------------------ */
+/* decNumberQuantize -- force exponent to requested value */
+/* */
+/* This computes C = op(A, B), where op adjusts the coefficient */
+/* of C (by rounding or shifting) such that the exponent (-scale) */
+/* of C has exponent of B. The numerical value of C will equal A, */
+/* except for the effects of any rounding that occurred. */
+/* */
+/* res is C, the result. C may be A or B */
+/* lhs is A, the number to adjust */
+/* rhs is B, the number with exponent to match */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* Unless there is an error or the result is infinite, the exponent */
+/* after the operation is guaranteed to be equal to that of B. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberQuantize(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decQuantizeOp(res, lhs, rhs, set, 1, &status);
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberQuantize */
+
+/* ------------------------------------------------------------------ */
+/* decNumberReduce -- remove trailing zeros */
+/* */
+/* This computes C = 0 + A, and normalizes the result */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+/* Previously known as Normalize */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberNormalize(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ return uprv_decNumberReduce(res, rhs, set);
+ } /* decNumberNormalize */
+
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberReduce(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ #if DECSUBSET
+ decNumber *allocrhs=NULL; /* non-NULL if rounded rhs allocated */
+ #endif
+ uInt status=0; /* as usual */
+ Int residue=0; /* as usual */
+ Int dropped; /* work */
+
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ do { /* protect allocated storage */
+ #if DECSUBSET
+ if (!set->extended) {
+ /* reduce operand and set lostDigits status, as needed */
+ if (rhs->digits>set->digits) {
+ allocrhs=decRoundOperand(rhs, set, &status);
+ if (allocrhs==NULL) break;
+ rhs=allocrhs;
+ }
+ }
+ #endif
+ /* [following code does not require input rounding] */
+
+ /* Infinities copy through; NaNs need usual treatment */
+ if (decNumberIsNaN(rhs)) {
+ decNaNs(res, rhs, NULL, set, &status);
+ break;
+ }
+
+ /* reduce result to the requested length and copy to result */
+ decCopyFit(res, rhs, set, &residue, &status); /* copy & round */
+ decFinish(res, set, &residue, &status); /* cleanup/set flags */
+ decTrim(res, set, 1, 0, &dropped); /* normalize in place */
+ /* [may clamp] */
+ } while(0); /* end protected */
+
+ #if DECSUBSET
+ if (allocrhs !=NULL) free(allocrhs); /* .. */
+ #endif
+ if (status!=0) decStatus(res, status, set);/* then report status */
+ return res;
+ } /* decNumberReduce */
+
+/* ------------------------------------------------------------------ */
+/* decNumberRescale -- force exponent to requested value */
+/* */
+/* This computes C = op(A, B), where op adjusts the coefficient */
+/* of C (by rounding or shifting) such that the exponent (-scale) */
+/* of C has the value B. The numerical value of C will equal A, */
+/* except for the effects of any rounding that occurred. */
+/* */
+/* res is C, the result. C may be A or B */
+/* lhs is A, the number to adjust */
+/* rhs is B, the requested exponent */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* Unless there is an error or the result is infinite, the exponent */
+/* after the operation is guaranteed to be equal to B. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberRescale(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decQuantizeOp(res, lhs, rhs, set, 0, &status);
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberRescale */
+
+/* ------------------------------------------------------------------ */
+/* decNumberRemainder -- divide and return remainder */
+/* */
+/* This computes C = A % B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X%X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberRemainder(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decDivideOp(res, lhs, rhs, set, REMAINDER, &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberRemainder */
+
+/* ------------------------------------------------------------------ */
+/* decNumberRemainderNear -- divide and return remainder from nearest */
+/* */
+/* This computes C = A % B, where % is the IEEE remainder operator */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X%X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberRemainderNear(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ decDivideOp(res, lhs, rhs, set, REMNEAR, &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberRemainderNear */
+
+/* ------------------------------------------------------------------ */
+/* decNumberRotate -- rotate the coefficient of a Number left/right */
+/* */
+/* This computes C = A rot B (in base ten and rotating set->digits */
+/* digits). */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=XrotX) */
+/* lhs is A */
+/* rhs is B, the number of digits to rotate (-ve to right) */
+/* set is the context */
+/* */
+/* The digits of the coefficient of A are rotated to the left (if B */
+/* is positive) or to the right (if B is negative) without adjusting */
+/* the exponent or the sign of A. If lhs->digits is less than */
+/* set->digits the coefficient is padded with zeros on the left */
+/* before the rotate. Any leading zeros in the result are removed */
+/* as usual. */
+/* */
+/* B must be an integer (q=0) and in the range -set->digits through */
+/* +set->digits. */
+/* C must have space for set->digits digits. */
+/* NaNs are propagated as usual. Infinities are unaffected (but */
+/* B must be valid). No status is set unless B is invalid or an */
+/* operand is an sNaN. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberRotate(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ Int rotate; /* rhs as an Int */
+
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ /* NaNs propagate as normal */
+ if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs))
+ decNaNs(res, lhs, rhs, set, &status);
+ /* rhs must be an integer */
+ else if (decNumberIsInfinite(rhs) || rhs->exponent!=0)
+ status=DEC_Invalid_operation;
+ else { /* both numeric, rhs is an integer */
+ rotate=decGetInt(rhs); /* [cannot fail] */
+ if (rotate==BADINT /* something bad .. */
+ || rotate==BIGODD || rotate==BIGEVEN /* .. very big .. */
+ || abs(rotate)>set->digits) /* .. or out of range */
+ status=DEC_Invalid_operation;
+ else { /* rhs is OK */
+ uprv_decNumberCopy(res, lhs);
+ /* convert -ve rotate to equivalent positive rotation */
+ if (rotate<0) rotate=set->digits+rotate;
+ if (rotate!=0 && rotate!=set->digits /* zero or full rotation */
+ && !decNumberIsInfinite(res)) { /* lhs was infinite */
+ /* left-rotate to do; 0 < rotate < set->digits */
+ uInt units, shift; /* work */
+ uInt msudigits; /* digits in result msu */
+ Unit *msu=res->lsu+D2U(res->digits)-1; /* current msu */
+ Unit *msumax=res->lsu+D2U(set->digits)-1; /* rotation msu */
+ for (msu++; msu<=msumax; msu++) *msu=0; /* ensure high units=0 */
+ res->digits=set->digits; /* now full-length */
+ msudigits=MSUDIGITS(res->digits); /* actual digits in msu */
+
+ /* rotation here is done in-place, in three steps */
+ /* 1. shift all to least up to one unit to unit-align final */
+ /* lsd [any digits shifted out are rotated to the left, */
+ /* abutted to the original msd (which may require split)] */
+ /* */
+ /* [if there are no whole units left to rotate, the */
+ /* rotation is now complete] */
+ /* */
+ /* 2. shift to least, from below the split point only, so that */
+ /* the final msd is in the right place in its Unit [any */
+ /* digits shifted out will fit exactly in the current msu, */
+ /* left aligned, no split required] */
+ /* */
+ /* 3. rotate all the units by reversing left part, right */
+ /* part, and then whole */
+ /* */
+ /* example: rotate right 8 digits (2 units + 2), DECDPUN=3. */
+ /* */
+ /* start: 00a bcd efg hij klm npq */
+ /* */
+ /* 1a 000 0ab cde fgh|ijk lmn [pq saved] */
+ /* 1b 00p qab cde fgh|ijk lmn */
+ /* */
+ /* 2a 00p qab cde fgh|00i jkl [mn saved] */
+ /* 2b mnp qab cde fgh|00i jkl */
+ /* */
+ /* 3a fgh cde qab mnp|00i jkl */
+ /* 3b fgh cde qab mnp|jkl 00i */
+ /* 3c 00i jkl mnp qab cde fgh */
+
+ /* Step 1: amount to shift is the partial right-rotate count */
+ rotate=set->digits-rotate; /* make it right-rotate */
+ units=rotate/DECDPUN; /* whole units to rotate */
+ shift=rotate%DECDPUN; /* left-over digits count */
+ if (shift>0) { /* not an exact number of units */
+ uInt save=res->lsu[0]%powers[shift]; /* save low digit(s) */
+ decShiftToLeast(res->lsu, D2U(res->digits), shift);
+ if (shift>msudigits) { /* msumax-1 needs >0 digits */
+ uInt rem=save%powers[shift-msudigits];/* split save */
+ *msumax=(Unit)(save/powers[shift-msudigits]); /* and insert */
+ *(msumax-1)=*(msumax-1)
+ +(Unit)(rem*powers[DECDPUN-(shift-msudigits)]); /* .. */
+ }
+ else { /* all fits in msumax */
+ *msumax=*msumax+(Unit)(save*powers[msudigits-shift]); /* [maybe *1] */
+ }
+ } /* digits shift needed */
+
+ /* If whole units to rotate... */
+ if (units>0) { /* some to do */
+ /* Step 2: the units to touch are the whole ones in rotate, */
+ /* if any, and the shift is DECDPUN-msudigits (which may be */
+ /* 0, again) */
+ shift=DECDPUN-msudigits;
+ if (shift>0) { /* not an exact number of units */
+ uInt save=res->lsu[0]%powers[shift]; /* save low digit(s) */
+ decShiftToLeast(res->lsu, units, shift);
+ *msumax=*msumax+(Unit)(save*powers[msudigits]);
+ } /* partial shift needed */
+
+ /* Step 3: rotate the units array using triple reverse */
+ /* (reversing is easy and fast) */
+ decReverse(res->lsu+units, msumax); /* left part */
+ decReverse(res->lsu, res->lsu+units-1); /* right part */
+ decReverse(res->lsu, msumax); /* whole */
+ } /* whole units to rotate */
+ /* the rotation may have left an undetermined number of zeros */
+ /* on the left, so true length needs to be calculated */
+ res->digits=decGetDigits(res->lsu, static_cast<int32_t>(msumax-res->lsu+1));
+ } /* rotate needed */
+ } /* rhs OK */
+ } /* numerics */
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberRotate */
+
+/* ------------------------------------------------------------------ */
+/* decNumberSameQuantum -- test for equal exponents */
+/* */
+/* res is the result number, which will contain either 0 or 1 */
+/* lhs is a number to test */
+/* rhs is the second (usually a pattern) */
+/* */
+/* No errors are possible and no context is needed. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberSameQuantum(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs) {
+ Unit ret=0; /* return value */
+
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, DECUNCONT)) return res;
+ #endif
+
+ if (SPECIALARGS) {
+ if (decNumberIsNaN(lhs) && decNumberIsNaN(rhs)) ret=1;
+ else if (decNumberIsInfinite(lhs) && decNumberIsInfinite(rhs)) ret=1;
+ /* [anything else with a special gives 0] */
+ }
+ else if (lhs->exponent==rhs->exponent) ret=1;
+
+ uprv_decNumberZero(res); /* OK to overwrite an operand now */
+ *res->lsu=ret;
+ return res;
+ } /* decNumberSameQuantum */
+
+/* ------------------------------------------------------------------ */
+/* decNumberScaleB -- multiply by a power of 10 */
+/* */
+/* This computes C = A x 10**B where B is an integer (q=0) with */
+/* maximum magnitude 2*(emax+digits) */
+/* */
+/* res is C, the result. C may be A or B */
+/* lhs is A, the number to adjust */
+/* rhs is B, the requested power of ten to use */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* The result may underflow or overflow. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberScaleB(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ Int reqexp; /* requested exponent change [B] */
+ uInt status=0; /* accumulator */
+ Int residue; /* work */
+
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ /* Handle special values except lhs infinite */
+ if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs))
+ decNaNs(res, lhs, rhs, set, &status);
+ /* rhs must be an integer */
+ else if (decNumberIsInfinite(rhs) || rhs->exponent!=0)
+ status=DEC_Invalid_operation;
+ else {
+ /* lhs is a number; rhs is a finite with q==0 */
+ reqexp=decGetInt(rhs); /* [cannot fail] */
+ if (reqexp==BADINT /* something bad .. */
+ || reqexp==BIGODD || reqexp==BIGEVEN /* .. very big .. */
+ || abs(reqexp)>(2*(set->digits+set->emax))) /* .. or out of range */
+ status=DEC_Invalid_operation;
+ else { /* rhs is OK */
+ uprv_decNumberCopy(res, lhs); /* all done if infinite lhs */
+ if (!decNumberIsInfinite(res)) { /* prepare to scale */
+ res->exponent+=reqexp; /* adjust the exponent */
+ residue=0;
+ decFinalize(res, set, &residue, &status); /* .. and check */
+ } /* finite LHS */
+ } /* rhs OK */
+ } /* rhs finite */
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberScaleB */
+
+/* ------------------------------------------------------------------ */
+/* decNumberShift -- shift the coefficient of a Number left or right */
+/* */
+/* This computes C = A << B or C = A >> -B (in base ten). */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X<<X) */
+/* lhs is A */
+/* rhs is B, the number of digits to shift (-ve to right) */
+/* set is the context */
+/* */
+/* The digits of the coefficient of A are shifted to the left (if B */
+/* is positive) or to the right (if B is negative) without adjusting */
+/* the exponent or the sign of A. */
+/* */
+/* B must be an integer (q=0) and in the range -set->digits through */
+/* +set->digits. */
+/* C must have space for set->digits digits. */
+/* NaNs are propagated as usual. Infinities are unaffected (but */
+/* B must be valid). No status is set unless B is invalid or an */
+/* operand is an sNaN. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberShift(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+ Int shift; /* rhs as an Int */
+
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ /* NaNs propagate as normal */
+ if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs))
+ decNaNs(res, lhs, rhs, set, &status);
+ /* rhs must be an integer */
+ else if (decNumberIsInfinite(rhs) || rhs->exponent!=0)
+ status=DEC_Invalid_operation;
+ else { /* both numeric, rhs is an integer */
+ shift=decGetInt(rhs); /* [cannot fail] */
+ if (shift==BADINT /* something bad .. */
+ || shift==BIGODD || shift==BIGEVEN /* .. very big .. */
+ || abs(shift)>set->digits) /* .. or out of range */
+ status=DEC_Invalid_operation;
+ else { /* rhs is OK */
+ uprv_decNumberCopy(res, lhs);
+ if (shift!=0 && !decNumberIsInfinite(res)) { /* something to do */
+ if (shift>0) { /* to left */
+ if (shift==set->digits) { /* removing all */
+ *res->lsu=0; /* so place 0 */
+ res->digits=1; /* .. */
+ }
+ else { /* */
+ /* first remove leading digits if necessary */
+ if (res->digits+shift>set->digits) {
+ decDecap(res, res->digits+shift-set->digits);
+ /* that updated res->digits; may have gone to 1 (for a */
+ /* single digit or for zero */
+ }
+ if (res->digits>1 || *res->lsu) /* if non-zero.. */
+ res->digits=decShiftToMost(res->lsu, res->digits, shift);
+ } /* partial left */
+ } /* left */
+ else { /* to right */
+ if (-shift>=res->digits) { /* discarding all */
+ *res->lsu=0; /* so place 0 */
+ res->digits=1; /* .. */
+ }
+ else {
+ decShiftToLeast(res->lsu, D2U(res->digits), -shift);
+ res->digits-=(-shift);
+ }
+ } /* to right */
+ } /* non-0 non-Inf shift */
+ } /* rhs OK */
+ } /* numerics */
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberShift */
+
+/* ------------------------------------------------------------------ */
+/* decNumberSquareRoot -- square root operator */
+/* */
+/* This computes C = squareroot(A) */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context; note that rounding mode has no effect */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+/* This uses the following varying-precision algorithm in: */
+/* */
+/* Properly Rounded Variable Precision Square Root, T. E. Hull and */
+/* A. Abrham, ACM Transactions on Mathematical Software, Vol 11 #3, */
+/* pp229-237, ACM, September 1985. */
+/* */
+/* The square-root is calculated using Newton's method, after which */
+/* a check is made to ensure the result is correctly rounded. */
+/* */
+/* % [Reformatted original Numerical Turing source code follows.] */
+/* function sqrt(x : real) : real */
+/* % sqrt(x) returns the properly rounded approximation to the square */
+/* % root of x, in the precision of the calling environment, or it */
+/* % fails if x < 0. */
+/* % t e hull and a abrham, august, 1984 */
+/* if x <= 0 then */
+/* if x < 0 then */
+/* assert false */
+/* else */
+/* result 0 */
+/* end if */
+/* end if */
+/* var f := setexp(x, 0) % fraction part of x [0.1 <= x < 1] */
+/* var e := getexp(x) % exponent part of x */
+/* var approx : real */
+/* if e mod 2 = 0 then */
+/* approx := .259 + .819 * f % approx to root of f */
+/* else */
+/* f := f/l0 % adjustments */
+/* e := e + 1 % for odd */
+/* approx := .0819 + 2.59 * f % exponent */
+/* end if */
+/* */
+/* var p:= 3 */
+/* const maxp := currentprecision + 2 */
+/* loop */
+/* p := min(2*p - 2, maxp) % p = 4,6,10, . . . , maxp */
+/* precision p */
+/* approx := .5 * (approx + f/approx) */
+/* exit when p = maxp */
+/* end loop */
+/* */
+/* % approx is now within 1 ulp of the properly rounded square root */
+/* % of f; to ensure proper rounding, compare squares of (approx - */
+/* % l/2 ulp) and (approx + l/2 ulp) with f. */
+/* p := currentprecision */
+/* begin */
+/* precision p + 2 */
+/* const approxsubhalf := approx - setexp(.5, -p) */
+/* if mulru(approxsubhalf, approxsubhalf) > f then */
+/* approx := approx - setexp(.l, -p + 1) */
+/* else */
+/* const approxaddhalf := approx + setexp(.5, -p) */
+/* if mulrd(approxaddhalf, approxaddhalf) < f then */
+/* approx := approx + setexp(.l, -p + 1) */
+/* end if */
+/* end if */
+/* end */
+/* result setexp(approx, e div 2) % fix exponent */
+/* end sqrt */
+/* ------------------------------------------------------------------ */
+#if defined(__clang__) || U_GCC_MAJOR_MINOR >= 406
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
+#endif
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberSquareRoot(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ decContext workset, approxset; /* work contexts */
+ decNumber dzero; /* used for constant zero */
+ Int maxp; /* largest working precision */
+ Int workp; /* working precision */
+ Int residue=0; /* rounding residue */
+ uInt status=0, ignore=0; /* status accumulators */
+ uInt rstatus; /* .. */
+ Int exp; /* working exponent */
+ Int ideal; /* ideal (preferred) exponent */
+ Int needbytes; /* work */
+ Int dropped; /* .. */
+
+ #if DECSUBSET
+ decNumber *allocrhs=NULL; /* non-NULL if rounded rhs allocated */
+ #endif
+ /* buffer for f [needs +1 in case DECBUFFER 0] */
+ decNumber buff[D2N(DECBUFFER+1)];
+ /* buffer for a [needs +2 to match likely maxp] */
+ decNumber bufa[D2N(DECBUFFER+2)];
+ /* buffer for temporary, b [must be same size as a] */
+ decNumber bufb[D2N(DECBUFFER+2)];
+ decNumber *allocbuff=NULL; /* -> allocated buff, iff allocated */
+ decNumber *allocbufa=NULL; /* -> allocated bufa, iff allocated */
+ decNumber *allocbufb=NULL; /* -> allocated bufb, iff allocated */
+ decNumber *f=buff; /* reduced fraction */
+ decNumber *a=bufa; /* approximation to result */
+ decNumber *b=bufb; /* intermediate result */
+ /* buffer for temporary variable, up to 3 digits */
+ decNumber buft[D2N(3)];
+ decNumber *t=buft; /* up-to-3-digit constant or work */
+
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ do { /* protect allocated storage */
+ #if DECSUBSET
+ if (!set->extended) {
+ /* reduce operand and set lostDigits status, as needed */
+ if (rhs->digits>set->digits) {
+ allocrhs=decRoundOperand(rhs, set, &status);
+ if (allocrhs==NULL) break;
+ /* [Note: 'f' allocation below could reuse this buffer if */
+ /* used, but as this is rare they are kept separate for clarity.] */
+ rhs=allocrhs;
+ }
+ }
+ #endif
+ /* [following code does not require input rounding] */
+
+ /* handle infinities and NaNs */
+ if (SPECIALARG) {
+ if (decNumberIsInfinite(rhs)) { /* an infinity */
+ if (decNumberIsNegative(rhs)) status|=DEC_Invalid_operation;
+ else uprv_decNumberCopy(res, rhs); /* +Infinity */
+ }
+ else decNaNs(res, rhs, NULL, set, &status); /* a NaN */
+ break;
+ }
+
+ /* calculate the ideal (preferred) exponent [floor(exp/2)] */
+ /* [It would be nicer to write: ideal=rhs->exponent>>1, but this */
+ /* generates a compiler warning. Generated code is the same.] */
+ ideal=(rhs->exponent&~1)/2; /* target */
+
+ /* handle zeros */
+ if (ISZERO(rhs)) {
+ uprv_decNumberCopy(res, rhs); /* could be 0 or -0 */
+ res->exponent=ideal; /* use the ideal [safe] */
+ /* use decFinish to clamp any out-of-range exponent, etc. */
+ decFinish(res, set, &residue, &status);
+ break;
+ }
+
+ /* any other -x is an oops */
+ if (decNumberIsNegative(rhs)) {
+ status|=DEC_Invalid_operation;
+ break;
+ }
+
+ /* space is needed for three working variables */
+ /* f -- the same precision as the RHS, reduced to 0.01->0.99... */
+ /* a -- Hull's approximation -- precision, when assigned, is */
+ /* currentprecision+1 or the input argument precision, */
+ /* whichever is larger (+2 for use as temporary) */
+ /* b -- intermediate temporary result (same size as a) */
+ /* if any is too long for local storage, then allocate */
+ workp=MAXI(set->digits+1, rhs->digits); /* actual rounding precision */
+ workp=MAXI(workp, 7); /* at least 7 for low cases */
+ maxp=workp+2; /* largest working precision */
+
+ needbytes=sizeof(decNumber)+(D2U(rhs->digits)-1)*sizeof(Unit);
+ if (needbytes>(Int)sizeof(buff)) {
+ allocbuff=(decNumber *)malloc(needbytes);
+ if (allocbuff==NULL) { /* hopeless -- abandon */
+ status|=DEC_Insufficient_storage;
+ break;}
+ f=allocbuff; /* use the allocated space */
+ }
+ /* a and b both need to be able to hold a maxp-length number */
+ needbytes=sizeof(decNumber)+(D2U(maxp)-1)*sizeof(Unit);
+ if (needbytes>(Int)sizeof(bufa)) { /* [same applies to b] */
+ allocbufa=(decNumber *)malloc(needbytes);
+ allocbufb=(decNumber *)malloc(needbytes);
+ if (allocbufa==NULL || allocbufb==NULL) { /* hopeless */
+ status|=DEC_Insufficient_storage;
+ break;}
+ a=allocbufa; /* use the allocated spaces */
+ b=allocbufb; /* .. */
+ }
+
+ /* copy rhs -> f, save exponent, and reduce so 0.1 <= f < 1 */
+ uprv_decNumberCopy(f, rhs);
+ exp=f->exponent+f->digits; /* adjusted to Hull rules */
+ f->exponent=-(f->digits); /* to range */
+
+ /* set up working context */
+ uprv_decContextDefault(&workset, DEC_INIT_DECIMAL64);
+ workset.emax=DEC_MAX_EMAX;
+ workset.emin=DEC_MIN_EMIN;
+
+ /* [Until further notice, no error is possible and status bits */
+ /* (Rounded, etc.) should be ignored, not accumulated.] */
+
+ /* Calculate initial approximation, and allow for odd exponent */
+ workset.digits=workp; /* p for initial calculation */
+ t->bits=0; t->digits=3;
+ a->bits=0; a->digits=3;
+ if ((exp & 1)==0) { /* even exponent */
+ /* Set t=0.259, a=0.819 */
+ t->exponent=-3;
+ a->exponent=-3;
+ #if DECDPUN>=3
+ t->lsu[0]=259;
+ a->lsu[0]=819;
+ #elif DECDPUN==2
+ t->lsu[0]=59; t->lsu[1]=2;
+ a->lsu[0]=19; a->lsu[1]=8;
+ #else
+ t->lsu[0]=9; t->lsu[1]=5; t->lsu[2]=2;
+ a->lsu[0]=9; a->lsu[1]=1; a->lsu[2]=8;
+ #endif
+ }
+ else { /* odd exponent */
+ /* Set t=0.0819, a=2.59 */
+ f->exponent--; /* f=f/10 */
+ exp++; /* e=e+1 */
+ t->exponent=-4;
+ a->exponent=-2;
+ #if DECDPUN>=3
+ t->lsu[0]=819;
+ a->lsu[0]=259;
+ #elif DECDPUN==2
+ t->lsu[0]=19; t->lsu[1]=8;
+ a->lsu[0]=59; a->lsu[1]=2;
+ #else
+ t->lsu[0]=9; t->lsu[1]=1; t->lsu[2]=8;
+ a->lsu[0]=9; a->lsu[1]=5; a->lsu[2]=2;
+ #endif
+ }
+
+ decMultiplyOp(a, a, f, &workset, &ignore); /* a=a*f */
+ decAddOp(a, a, t, &workset, 0, &ignore); /* ..+t */
+ /* [a is now the initial approximation for sqrt(f), calculated with */
+ /* currentprecision, which is also a's precision.] */
+
+ /* the main calculation loop */
+ uprv_decNumberZero(&dzero); /* make 0 */
+ uprv_decNumberZero(t); /* set t = 0.5 */
+ t->lsu[0]=5; /* .. */
+ t->exponent=-1; /* .. */
+ workset.digits=3; /* initial p */
+ for (; workset.digits<maxp;) {
+ /* set p to min(2*p - 2, maxp) [hence 3; or: 4, 6, 10, ... , maxp] */
+ workset.digits=MINI(workset.digits*2-2, maxp);
+ /* a = 0.5 * (a + f/a) */
+ /* [calculated at p then rounded to currentprecision] */
+ decDivideOp(b, f, a, &workset, DIVIDE, &ignore); /* b=f/a */
+ decAddOp(b, b, a, &workset, 0, &ignore); /* b=b+a */
+ decMultiplyOp(a, b, t, &workset, &ignore); /* a=b*0.5 */
+ } /* loop */
+
+ /* Here, 0.1 <= a < 1 [Hull], and a has maxp digits */
+ /* now reduce to length, etc.; this needs to be done with a */
+ /* having the correct exponent so as to handle subnormals */
+ /* correctly */
+ approxset=*set; /* get emin, emax, etc. */
+ approxset.round=DEC_ROUND_HALF_EVEN;
+ a->exponent+=exp/2; /* set correct exponent */
+ rstatus=0; /* clear status */
+ residue=0; /* .. and accumulator */
+ decCopyFit(a, a, &approxset, &residue, &rstatus); /* reduce (if needed) */
+ decFinish(a, &approxset, &residue, &rstatus); /* clean and finalize */
+
+ /* Overflow was possible if the input exponent was out-of-range, */
+ /* in which case quit */
+ if (rstatus&DEC_Overflow) {
+ status=rstatus; /* use the status as-is */
+ uprv_decNumberCopy(res, a); /* copy to result */
+ break;
+ }
+
+ /* Preserve status except Inexact/Rounded */
+ status|=(rstatus & ~(DEC_Rounded|DEC_Inexact));
+
+ /* Carry out the Hull correction */
+ a->exponent-=exp/2; /* back to 0.1->1 */
+
+ /* a is now at final precision and within 1 ulp of the properly */
+ /* rounded square root of f; to ensure proper rounding, compare */
+ /* squares of (a - l/2 ulp) and (a + l/2 ulp) with f. */
+ /* Here workset.digits=maxp and t=0.5, and a->digits determines */
+ /* the ulp */
+ workset.digits--; /* maxp-1 is OK now */
+ t->exponent=-a->digits-1; /* make 0.5 ulp */
+ decAddOp(b, a, t, &workset, DECNEG, &ignore); /* b = a - 0.5 ulp */
+ workset.round=DEC_ROUND_UP;
+ decMultiplyOp(b, b, b, &workset, &ignore); /* b = mulru(b, b) */
+ decCompareOp(b, f, b, &workset, COMPARE, &ignore); /* b ? f, reversed */
+ if (decNumberIsNegative(b)) { /* f < b [i.e., b > f] */
+ /* this is the more common adjustment, though both are rare */
+ t->exponent++; /* make 1.0 ulp */
+ t->lsu[0]=1; /* .. */
+ decAddOp(a, a, t, &workset, DECNEG, &ignore); /* a = a - 1 ulp */
+ /* assign to approx [round to length] */
+ approxset.emin-=exp/2; /* adjust to match a */
+ approxset.emax-=exp/2;
+ decAddOp(a, &dzero, a, &approxset, 0, &ignore);
+ }
+ else {
+ decAddOp(b, a, t, &workset, 0, &ignore); /* b = a + 0.5 ulp */
+ workset.round=DEC_ROUND_DOWN;
+ decMultiplyOp(b, b, b, &workset, &ignore); /* b = mulrd(b, b) */
+ decCompareOp(b, b, f, &workset, COMPARE, &ignore); /* b ? f */
+ if (decNumberIsNegative(b)) { /* b < f */
+ t->exponent++; /* make 1.0 ulp */
+ t->lsu[0]=1; /* .. */
+ decAddOp(a, a, t, &workset, 0, &ignore); /* a = a + 1 ulp */
+ /* assign to approx [round to length] */
+ approxset.emin-=exp/2; /* adjust to match a */
+ approxset.emax-=exp/2;
+ decAddOp(a, &dzero, a, &approxset, 0, &ignore);
+ }
+ }
+ /* [no errors are possible in the above, and rounding/inexact during */
+ /* estimation are irrelevant, so status was not accumulated] */
+
+ /* Here, 0.1 <= a < 1 (still), so adjust back */
+ a->exponent+=exp/2; /* set correct exponent */
+
+ /* count droppable zeros [after any subnormal rounding] by */
+ /* trimming a copy */
+ uprv_decNumberCopy(b, a);
+ decTrim(b, set, 1, 1, &dropped); /* [drops trailing zeros] */
+
+ /* Set Inexact and Rounded. The answer can only be exact if */
+ /* it is short enough so that squaring it could fit in workp */
+ /* digits, so this is the only (relatively rare) condition that */
+ /* a careful check is needed */
+ if (b->digits*2-1 > workp) { /* cannot fit */
+ status|=DEC_Inexact|DEC_Rounded;
+ }
+ else { /* could be exact/unrounded */
+ uInt mstatus=0; /* local status */
+ decMultiplyOp(b, b, b, &workset, &mstatus); /* try the multiply */
+ if (mstatus&DEC_Overflow) { /* result just won't fit */
+ status|=DEC_Inexact|DEC_Rounded;
+ }
+ else { /* plausible */
+ decCompareOp(t, b, rhs, &workset, COMPARE, &mstatus); /* b ? rhs */
+ if (!ISZERO(t)) status|=DEC_Inexact|DEC_Rounded; /* not equal */
+ else { /* is Exact */
+ /* here, dropped is the count of trailing zeros in 'a' */
+ /* use closest exponent to ideal... */
+ Int todrop=ideal-a->exponent; /* most that can be dropped */
+ if (todrop<0) status|=DEC_Rounded; /* ideally would add 0s */
+ else { /* unrounded */
+ /* there are some to drop, but emax may not allow all */
+ Int maxexp=set->emax-set->digits+1;
+ Int maxdrop=maxexp-a->exponent;
+ if (todrop>maxdrop && set->clamp) { /* apply clamping */
+ todrop=maxdrop;
+ status|=DEC_Clamped;
+ }
+ if (dropped<todrop) { /* clamp to those available */
+ todrop=dropped;
+ status|=DEC_Clamped;
+ }
+ if (todrop>0) { /* have some to drop */
+ decShiftToLeast(a->lsu, D2U(a->digits), todrop);
+ a->exponent+=todrop; /* maintain numerical value */
+ a->digits-=todrop; /* new length */
+ }
+ }
+ }
+ }
+ }
+
+ /* double-check Underflow, as perhaps the result could not have */
+ /* been subnormal (initial argument too big), or it is now Exact */
+ if (status&DEC_Underflow) {
+ Int ae=rhs->exponent+rhs->digits-1; /* adjusted exponent */
+ /* check if truly subnormal */
+ #if DECEXTFLAG /* DEC_Subnormal too */
+ if (ae>=set->emin*2) status&=~(DEC_Subnormal|DEC_Underflow);
+ #else
+ if (ae>=set->emin*2) status&=~DEC_Underflow;
+ #endif
+ /* check if truly inexact */
+ if (!(status&DEC_Inexact)) status&=~DEC_Underflow;
+ }
+
+ uprv_decNumberCopy(res, a); /* a is now the result */
+ } while(0); /* end protected */
+
+ if (allocbuff!=NULL) free(allocbuff); /* drop any storage used */
+ if (allocbufa!=NULL) free(allocbufa); /* .. */
+ if (allocbufb!=NULL) free(allocbufb); /* .. */
+ #if DECSUBSET
+ if (allocrhs !=NULL) free(allocrhs); /* .. */
+ #endif
+ if (status!=0) decStatus(res, status, set);/* then report status */
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberSquareRoot */
+#if defined(__clang__) || U_GCC_MAJOR_MINOR >= 406
+#pragma GCC diagnostic pop
+#endif
+
+/* ------------------------------------------------------------------ */
+/* decNumberSubtract -- subtract two Numbers */
+/* */
+/* This computes C = A - B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X-X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* */
+/* C must have space for set->digits digits. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberSubtract(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ uInt status=0; /* accumulator */
+
+ decAddOp(res, lhs, rhs, set, DECNEG, &status);
+ if (status!=0) decStatus(res, status, set);
+ #if DECCHECK
+ decCheckInexact(res, set);
+ #endif
+ return res;
+ } /* decNumberSubtract */
+
+/* ------------------------------------------------------------------ */
+/* decNumberToIntegralExact -- round-to-integral-value with InExact */
+/* decNumberToIntegralValue -- round-to-integral-value */
+/* */
+/* res is the result */
+/* rhs is input number */
+/* set is the context */
+/* */
+/* res must have space for any value of rhs. */
+/* */
+/* This implements the IEEE special operators and therefore treats */
+/* special values as valid. For finite numbers it returns */
+/* rescale(rhs, 0) if rhs->exponent is <0. */
+/* Otherwise the result is rhs (so no error is possible, except for */
+/* sNaN). */
+/* */
+/* The context is used for rounding mode and status after sNaN, but */
+/* the digits setting is ignored. The Exact version will signal */
+/* Inexact if the result differs numerically from rhs; the other */
+/* never signals Inexact. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberToIntegralExact(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ decNumber dn;
+ decContext workset; /* working context */
+ uInt status=0; /* accumulator */
+
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ /* handle infinities and NaNs */
+ if (SPECIALARG) {
+ if (decNumberIsInfinite(rhs)) uprv_decNumberCopy(res, rhs); /* an Infinity */
+ else decNaNs(res, rhs, NULL, set, &status); /* a NaN */
+ }
+ else { /* finite */
+ /* have a finite number; no error possible (res must be big enough) */
+ if (rhs->exponent>=0) return uprv_decNumberCopy(res, rhs);
+ /* that was easy, but if negative exponent there is work to do... */
+ workset=*set; /* clone rounding, etc. */
+ workset.digits=rhs->digits; /* no length rounding */
+ workset.traps=0; /* no traps */
+ uprv_decNumberZero(&dn); /* make a number with exponent 0 */
+ uprv_decNumberQuantize(res, rhs, &dn, &workset);
+ status|=workset.status;
+ }
+ if (status!=0) decStatus(res, status, set);
+ return res;
+ } /* decNumberToIntegralExact */
+
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberToIntegralValue(decNumber *res, const decNumber *rhs,
+ decContext *set) {
+ decContext workset=*set; /* working context */
+ workset.traps=0; /* no traps */
+ uprv_decNumberToIntegralExact(res, rhs, &workset);
+ /* this never affects set, except for sNaNs; NaN will have been set */
+ /* or propagated already, so no need to call decStatus */
+ set->status|=workset.status&DEC_Invalid_operation;
+ return res;
+ } /* decNumberToIntegralValue */
+
+/* ------------------------------------------------------------------ */
+/* decNumberXor -- XOR two Numbers, digitwise */
+/* */
+/* This computes C = A ^ B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X^X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context (used for result length and error report) */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* Logical function restrictions apply (see above); a NaN is */
+/* returned with Invalid_operation if a restriction is violated. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberXor(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ const Unit *ua, *ub; /* -> operands */
+ const Unit *msua, *msub; /* -> operand msus */
+ Unit *uc, *msuc; /* -> result and its msu */
+ Int msudigs; /* digits in res msu */
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ if (lhs->exponent!=0 || decNumberIsSpecial(lhs) || decNumberIsNegative(lhs)
+ || rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) {
+ decStatus(res, DEC_Invalid_operation, set);
+ return res;
+ }
+ /* operands are valid */
+ ua=lhs->lsu; /* bottom-up */
+ ub=rhs->lsu; /* .. */
+ uc=res->lsu; /* .. */
+ msua=ua+D2U(lhs->digits)-1; /* -> msu of lhs */
+ msub=ub+D2U(rhs->digits)-1; /* -> msu of rhs */
+ msuc=uc+D2U(set->digits)-1; /* -> msu of result */
+ msudigs=MSUDIGITS(set->digits); /* [faster than remainder] */
+ for (; uc<=msuc; ua++, ub++, uc++) { /* Unit loop */
+ Unit a, b; /* extract units */
+ if (ua>msua) a=0;
+ else a=*ua;
+ if (ub>msub) b=0;
+ else b=*ub;
+ *uc=0; /* can now write back */
+ if (a|b) { /* maybe 1 bits to examine */
+ Int i, j;
+ /* This loop could be unrolled and/or use BIN2BCD tables */
+ for (i=0; i<DECDPUN; i++) {
+ if ((a^b)&1) *uc=*uc+(Unit)powers[i]; /* effect XOR */
+ j=a%10;
+ a=a/10;
+ j|=b%10;
+ b=b/10;
+ if (j>1) {
+ decStatus(res, DEC_Invalid_operation, set);
+ return res;
+ }
+ if (uc==msuc && i==msudigs-1) break; /* just did final digit */
+ } /* each digit */
+ } /* non-zero */
+ } /* each unit */
+ /* [here uc-1 is the msu of the result] */
+ res->digits=decGetDigits(res->lsu, static_cast<int32_t>(uc-res->lsu));
+ res->exponent=0; /* integer */
+ res->bits=0; /* sign=0 */
+ return res; /* [no status to set] */
+ } /* decNumberXor */
+
+
+/* ================================================================== */
+/* Utility routines */
+/* ================================================================== */
+
+/* ------------------------------------------------------------------ */
+/* decNumberClass -- return the decClass of a decNumber */
+/* dn -- the decNumber to test */
+/* set -- the context to use for Emin */
+/* returns the decClass enum */
+/* ------------------------------------------------------------------ */
+enum decClass uprv_decNumberClass(const decNumber *dn, decContext *set) {
+ if (decNumberIsSpecial(dn)) {
+ if (decNumberIsQNaN(dn)) return DEC_CLASS_QNAN;
+ if (decNumberIsSNaN(dn)) return DEC_CLASS_SNAN;
+ /* must be an infinity */
+ if (decNumberIsNegative(dn)) return DEC_CLASS_NEG_INF;
+ return DEC_CLASS_POS_INF;
+ }
+ /* is finite */
+ if (uprv_decNumberIsNormal(dn, set)) { /* most common */
+ if (decNumberIsNegative(dn)) return DEC_CLASS_NEG_NORMAL;
+ return DEC_CLASS_POS_NORMAL;
+ }
+ /* is subnormal or zero */
+ if (decNumberIsZero(dn)) { /* most common */
+ if (decNumberIsNegative(dn)) return DEC_CLASS_NEG_ZERO;
+ return DEC_CLASS_POS_ZERO;
+ }
+ if (decNumberIsNegative(dn)) return DEC_CLASS_NEG_SUBNORMAL;
+ return DEC_CLASS_POS_SUBNORMAL;
+ } /* decNumberClass */
+
+/* ------------------------------------------------------------------ */
+/* decNumberClassToString -- convert decClass to a string */
+/* */
+/* eclass is a valid decClass */
+/* returns a constant string describing the class (max 13+1 chars) */
+/* ------------------------------------------------------------------ */
+const char *uprv_decNumberClassToString(enum decClass eclass) {
+ if (eclass==DEC_CLASS_POS_NORMAL) return DEC_ClassString_PN;
+ if (eclass==DEC_CLASS_NEG_NORMAL) return DEC_ClassString_NN;
+ if (eclass==DEC_CLASS_POS_ZERO) return DEC_ClassString_PZ;
+ if (eclass==DEC_CLASS_NEG_ZERO) return DEC_ClassString_NZ;
+ if (eclass==DEC_CLASS_POS_SUBNORMAL) return DEC_ClassString_PS;
+ if (eclass==DEC_CLASS_NEG_SUBNORMAL) return DEC_ClassString_NS;
+ if (eclass==DEC_CLASS_POS_INF) return DEC_ClassString_PI;
+ if (eclass==DEC_CLASS_NEG_INF) return DEC_ClassString_NI;
+ if (eclass==DEC_CLASS_QNAN) return DEC_ClassString_QN;
+ if (eclass==DEC_CLASS_SNAN) return DEC_ClassString_SN;
+ return DEC_ClassString_UN; /* Unknown */
+ } /* decNumberClassToString */
+
+/* ------------------------------------------------------------------ */
+/* decNumberCopy -- copy a number */
+/* */
+/* dest is the target decNumber */
+/* src is the source decNumber */
+/* returns dest */
+/* */
+/* (dest==src is allowed and is a no-op) */
+/* All fields are updated as required. This is a utility operation, */
+/* so special values are unchanged and no error is possible. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberCopy(decNumber *dest, const decNumber *src) {
+
+ #if DECCHECK
+ if (src==NULL) return uprv_decNumberZero(dest);
+ #endif
+
+ if (dest==src) return dest; /* no copy required */
+
+ /* Use explicit assignments here as structure assignment could copy */
+ /* more than just the lsu (for small DECDPUN). This would not affect */
+ /* the value of the results, but could disturb test harness spill */
+ /* checking. */
+ dest->bits=src->bits;
+ dest->exponent=src->exponent;
+ dest->digits=src->digits;
+ dest->lsu[0]=src->lsu[0];
+ if (src->digits>DECDPUN) { /* more Units to come */
+ const Unit *smsup, *s; /* work */
+ Unit *d; /* .. */
+ /* memcpy for the remaining Units would be safe as they cannot */
+ /* overlap. However, this explicit loop is faster in short cases. */
+ d=dest->lsu+1; /* -> first destination */
+ smsup=src->lsu+D2U(src->digits); /* -> source msu+1 */
+ for (s=src->lsu+1; s<smsup; s++, d++) *d=*s;
+ }
+ return dest;
+ } /* decNumberCopy */
+
+/* ------------------------------------------------------------------ */
+/* decNumberCopyAbs -- quiet absolute value operator */
+/* */
+/* This sets C = abs(A) */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* */
+/* C must have space for set->digits digits. */
+/* No exception or error can occur; this is a quiet bitwise operation.*/
+/* See also decNumberAbs for a checking version of this. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberCopyAbs(decNumber *res, const decNumber *rhs) {
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, DECUNCONT)) return res;
+ #endif
+ uprv_decNumberCopy(res, rhs);
+ res->bits&=~DECNEG; /* turn off sign */
+ return res;
+ } /* decNumberCopyAbs */
+
+/* ------------------------------------------------------------------ */
+/* decNumberCopyNegate -- quiet negate value operator */
+/* */
+/* This sets C = negate(A) */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* */
+/* C must have space for set->digits digits. */
+/* No exception or error can occur; this is a quiet bitwise operation.*/
+/* See also decNumberMinus for a checking version of this. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberCopyNegate(decNumber *res, const decNumber *rhs) {
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, DECUNCONT)) return res;
+ #endif
+ uprv_decNumberCopy(res, rhs);
+ res->bits^=DECNEG; /* invert the sign */
+ return res;
+ } /* decNumberCopyNegate */
+
+/* ------------------------------------------------------------------ */
+/* decNumberCopySign -- quiet copy and set sign operator */
+/* */
+/* This sets C = A with the sign of B */
+/* */
+/* res is C, the result. C may be A */
+/* lhs is A */
+/* rhs is B */
+/* */
+/* C must have space for set->digits digits. */
+/* No exception or error can occur; this is a quiet bitwise operation.*/
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberCopySign(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs) {
+ uByte sign; /* rhs sign */
+ #if DECCHECK
+ if (decCheckOperands(res, DECUNUSED, rhs, DECUNCONT)) return res;
+ #endif
+ sign=rhs->bits & DECNEG; /* save sign bit */
+ uprv_decNumberCopy(res, lhs);
+ res->bits&=~DECNEG; /* clear the sign */
+ res->bits|=sign; /* set from rhs */
+ return res;
+ } /* decNumberCopySign */
+
+/* ------------------------------------------------------------------ */
+/* decNumberGetBCD -- get the coefficient in BCD8 */
+/* dn is the source decNumber */
+/* bcd is the uInt array that will receive dn->digits BCD bytes, */
+/* most-significant at offset 0 */
+/* returns bcd */
+/* */
+/* bcd must have at least dn->digits bytes. No error is possible; if */
+/* dn is a NaN or Infinite, digits must be 1 and the coefficient 0. */
+/* ------------------------------------------------------------------ */
+U_CAPI uByte * U_EXPORT2 uprv_decNumberGetBCD(const decNumber *dn, uByte *bcd) {
+ uByte *ub=bcd+dn->digits-1; /* -> lsd */
+ const Unit *up=dn->lsu; /* Unit pointer, -> lsu */
+
+ #if DECDPUN==1 /* trivial simple copy */
+ for (; ub>=bcd; ub--, up++) *ub=*up;
+ #else /* chopping needed */
+ uInt u=*up; /* work */
+ uInt cut=DECDPUN; /* downcounter through unit */
+ for (; ub>=bcd; ub--) {
+ *ub=(uByte)(u%10); /* [*6554 trick inhibits, here] */
+ u=u/10;
+ cut--;
+ if (cut>0) continue; /* more in this unit */
+ up++;
+ u=*up;
+ cut=DECDPUN;
+ }
+ #endif
+ return bcd;
+ } /* decNumberGetBCD */
+
+/* ------------------------------------------------------------------ */
+/* decNumberSetBCD -- set (replace) the coefficient from BCD8 */
+/* dn is the target decNumber */
+/* bcd is the uInt array that will source n BCD bytes, most- */
+/* significant at offset 0 */
+/* n is the number of digits in the source BCD array (bcd) */
+/* returns dn */
+/* */
+/* dn must have space for at least n digits. No error is possible; */
+/* if dn is a NaN, or Infinite, or is to become a zero, n must be 1 */
+/* and bcd[0] zero. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberSetBCD(decNumber *dn, const uByte *bcd, uInt n) {
+ Unit *up=dn->lsu+D2U(dn->digits)-1; /* -> msu [target pointer] */
+ const uByte *ub=bcd; /* -> source msd */
+
+ #if DECDPUN==1 /* trivial simple copy */
+ for (; ub<bcd+n; ub++, up--) *up=*ub;
+ #else /* some assembly needed */
+ /* calculate how many digits in msu, and hence first cut */
+ Int cut=MSUDIGITS(n); /* [faster than remainder] */
+ for (;up>=dn->lsu; up--) { /* each Unit from msu */
+ *up=0; /* will take <=DECDPUN digits */
+ for (; cut>0; ub++, cut--) *up=X10(*up)+*ub;
+ cut=DECDPUN; /* next Unit has all digits */
+ }
+ #endif
+ dn->digits=n; /* set digit count */
+ return dn;
+ } /* decNumberSetBCD */
+
+/* ------------------------------------------------------------------ */
+/* decNumberIsNormal -- test normality of a decNumber */
+/* dn is the decNumber to test */
+/* set is the context to use for Emin */
+/* returns 1 if |dn| is finite and >=Nmin, 0 otherwise */
+/* ------------------------------------------------------------------ */
+Int uprv_decNumberIsNormal(const decNumber *dn, decContext *set) {
+ Int ae; /* adjusted exponent */
+ #if DECCHECK
+ if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0;
+ #endif
+
+ if (decNumberIsSpecial(dn)) return 0; /* not finite */
+ if (decNumberIsZero(dn)) return 0; /* not non-zero */
+
+ ae=dn->exponent+dn->digits-1; /* adjusted exponent */
+ if (ae<set->emin) return 0; /* is subnormal */
+ return 1;
+ } /* decNumberIsNormal */
+
+/* ------------------------------------------------------------------ */
+/* decNumberIsSubnormal -- test subnormality of a decNumber */
+/* dn is the decNumber to test */
+/* set is the context to use for Emin */
+/* returns 1 if |dn| is finite, non-zero, and <Nmin, 0 otherwise */
+/* ------------------------------------------------------------------ */
+Int uprv_decNumberIsSubnormal(const decNumber *dn, decContext *set) {
+ Int ae; /* adjusted exponent */
+ #if DECCHECK
+ if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0;
+ #endif
+
+ if (decNumberIsSpecial(dn)) return 0; /* not finite */
+ if (decNumberIsZero(dn)) return 0; /* not non-zero */
+
+ ae=dn->exponent+dn->digits-1; /* adjusted exponent */
+ if (ae<set->emin) return 1; /* is subnormal */
+ return 0;
+ } /* decNumberIsSubnormal */
+
+/* ------------------------------------------------------------------ */
+/* decNumberTrim -- remove insignificant zeros */
+/* */
+/* dn is the number to trim */
+/* returns dn */
+/* */
+/* All fields are updated as required. This is a utility operation, */
+/* so special values are unchanged and no error is possible. The */
+/* zeros are removed unconditionally. */
+/* ------------------------------------------------------------------ */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberTrim(decNumber *dn) {
+ Int dropped; /* work */
+ decContext set; /* .. */
+ #if DECCHECK
+ if (decCheckOperands(DECUNRESU, DECUNUSED, dn, DECUNCONT)) return dn;
+ #endif
+ uprv_decContextDefault(&set, DEC_INIT_BASE); /* clamp=0 */
+ return decTrim(dn, &set, 0, 1, &dropped);
+ } /* decNumberTrim */
+
+/* ------------------------------------------------------------------ */
+/* decNumberVersion -- return the name and version of this module */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+const char * uprv_decNumberVersion(void) {
+ return DECVERSION;
+ } /* decNumberVersion */
+
+/* ------------------------------------------------------------------ */
+/* decNumberZero -- set a number to 0 */
+/* */
+/* dn is the number to set, with space for one digit */
+/* returns dn */
+/* */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+/* Memset is not used as it is much slower in some environments. */
+U_CAPI decNumber * U_EXPORT2 uprv_decNumberZero(decNumber *dn) {
+
+ #if DECCHECK
+ if (decCheckOperands(dn, DECUNUSED, DECUNUSED, DECUNCONT)) return dn;
+ #endif
+
+ dn->bits=0;
+ dn->exponent=0;
+ dn->digits=1;
+ dn->lsu[0]=0;
+ return dn;
+ } /* decNumberZero */
+
+/* ================================================================== */
+/* Local routines */
+/* ================================================================== */
+
+/* ------------------------------------------------------------------ */
+/* decToString -- lay out a number into a string */
+/* */
+/* dn is the number to lay out */
+/* string is where to lay out the number */
+/* eng is 1 if Engineering, 0 if Scientific */
+/* */
+/* string must be at least dn->digits+14 characters long */
+/* No error is possible. */
+/* */
+/* Note that this routine can generate a -0 or 0.000. These are */
+/* never generated in subset to-number or arithmetic, but can occur */
+/* in non-subset arithmetic (e.g., -1*0 or 1.234-1.234). */
+/* ------------------------------------------------------------------ */
+/* If DECCHECK is enabled the string "?" is returned if a number is */
+/* invalid. */
+static void decToString(const decNumber *dn, char *string, Flag eng) {
+ Int exp=dn->exponent; /* local copy */
+ Int e; /* E-part value */
+ Int pre; /* digits before the '.' */
+ Int cut; /* for counting digits in a Unit */
+ char *c=string; /* work [output pointer] */
+ const Unit *up=dn->lsu+D2U(dn->digits)-1; /* -> msu [input pointer] */
+ uInt u, pow; /* work */
+
+ #if DECCHECK
+ if (decCheckOperands(DECUNRESU, dn, DECUNUSED, DECUNCONT)) {
+ strcpy(string, "?");
+ return;}
+ #endif
+
+ if (decNumberIsNegative(dn)) { /* Negatives get a minus */
+ *c='-';
+ c++;
+ }
+ if (dn->bits&DECSPECIAL) { /* Is a special value */
+ if (decNumberIsInfinite(dn)) {
+ strcpy(c, "Inf");
+ strcpy(c+3, "inity");
+ return;}
+ /* a NaN */
+ if (dn->bits&DECSNAN) { /* signalling NaN */
+ *c='s';
+ c++;
+ }
+ strcpy(c, "NaN");
+ c+=3; /* step past */
+ /* if not a clean non-zero coefficient, that's all there is in a */
+ /* NaN string */
+ if (exp!=0 || (*dn->lsu==0 && dn->digits==1)) return;
+ /* [drop through to add integer] */
+ }
+
+ /* calculate how many digits in msu, and hence first cut */
+ cut=MSUDIGITS(dn->digits); /* [faster than remainder] */
+ cut--; /* power of ten for digit */
+
+ if (exp==0) { /* simple integer [common fastpath] */
+ for (;up>=dn->lsu; up--) { /* each Unit from msu */
+ u=*up; /* contains DECDPUN digits to lay out */
+ for (; cut>=0; c++, cut--) TODIGIT(u, cut, c, pow);
+ cut=DECDPUN-1; /* next Unit has all digits */
+ }
+ *c='\0'; /* terminate the string */
+ return;}
+
+ /* non-0 exponent -- assume plain form */
+ pre=dn->digits+exp; /* digits before '.' */
+ e=0; /* no E */
+ if ((exp>0) || (pre<-5)) { /* need exponential form */
+ e=exp+dn->digits-1; /* calculate E value */
+ pre=1; /* assume one digit before '.' */
+ if (eng && (e!=0)) { /* engineering: may need to adjust */
+ Int adj; /* adjustment */
+ /* The C remainder operator is undefined for negative numbers, so */
+ /* a positive remainder calculation must be used here */
+ if (e<0) {
+ adj=(-e)%3;
+ if (adj!=0) adj=3-adj;
+ }
+ else { /* e>0 */
+ adj=e%3;
+ }
+ e=e-adj;
+ /* if dealing with zero still produce an exponent which is a */
+ /* multiple of three, as expected, but there will only be the */
+ /* one zero before the E, still. Otherwise note the padding. */
+ if (!ISZERO(dn)) pre+=adj;
+ else { /* is zero */
+ if (adj!=0) { /* 0.00Esnn needed */
+ e=e+3;
+ pre=-(2-adj);
+ }
+ } /* zero */
+ } /* eng */
+ } /* need exponent */
+
+ /* lay out the digits of the coefficient, adding 0s and . as needed */
+ u=*up;
+ if (pre>0) { /* xxx.xxx or xx00 (engineering) form */
+ Int n=pre;
+ for (; pre>0; pre--, c++, cut--) {
+ if (cut<0) { /* need new Unit */
+ if (up==dn->lsu) break; /* out of input digits (pre>digits) */
+ up--;
+ cut=DECDPUN-1;
+ u=*up;
+ }
+ TODIGIT(u, cut, c, pow);
+ }
+ if (n<dn->digits) { /* more to come, after '.' */
+ *c='.'; c++;
+ for (;; c++, cut--) {
+ if (cut<0) { /* need new Unit */
+ if (up==dn->lsu) break; /* out of input digits */
+ up--;
+ cut=DECDPUN-1;
+ u=*up;
+ }
+ TODIGIT(u, cut, c, pow);
+ }
+ }
+ else for (; pre>0; pre--, c++) *c='0'; /* 0 padding (for engineering) needed */
+ }
+ else { /* 0.xxx or 0.000xxx form */
+ *c='0'; c++;
+ *c='.'; c++;
+ for (; pre<0; pre++, c++) *c='0'; /* add any 0's after '.' */
+ for (; ; c++, cut--) {
+ if (cut<0) { /* need new Unit */
+ if (up==dn->lsu) break; /* out of input digits */
+ up--;
+ cut=DECDPUN-1;
+ u=*up;
+ }
+ TODIGIT(u, cut, c, pow);
+ }
+ }
+
+ /* Finally add the E-part, if needed. It will never be 0, has a
+ base maximum and minimum of +999999999 through -999999999, but
+ could range down to -1999999998 for anormal numbers */
+ if (e!=0) {
+ Flag had=0; /* 1=had non-zero */
+ *c='E'; c++;
+ *c='+'; c++; /* assume positive */
+ u=e; /* .. */
+ if (e<0) {
+ *(c-1)='-'; /* oops, need - */
+ u=-e; /* uInt, please */
+ }
+ /* lay out the exponent [_itoa or equivalent is not ANSI C] */
+ for (cut=9; cut>=0; cut--) {
+ TODIGIT(u, cut, c, pow);
+ if (*c=='0' && !had) continue; /* skip leading zeros */
+ had=1; /* had non-0 */
+ c++; /* step for next */
+ } /* cut */
+ }
+ *c='\0'; /* terminate the string (all paths) */
+ return;
+ } /* decToString */
+
+/* ------------------------------------------------------------------ */
+/* decAddOp -- add/subtract operation */
+/* */
+/* This computes C = A + B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X+X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* negate is DECNEG if rhs should be negated, or 0 otherwise */
+/* status accumulates status for the caller */
+/* */
+/* C must have space for set->digits digits. */
+/* Inexact in status must be 0 for correct Exact zero sign in result */
+/* ------------------------------------------------------------------ */
+/* If possible, the coefficient is calculated directly into C. */
+/* However, if: */
+/* -- a digits+1 calculation is needed because the numbers are */
+/* unaligned and span more than set->digits digits */
+/* -- a carry to digits+1 digits looks possible */
+/* -- C is the same as A or B, and the result would destructively */
+/* overlap the A or B coefficient */
+/* then the result must be calculated into a temporary buffer. In */
+/* this case a local (stack) buffer is used if possible, and only if */
+/* too long for that does malloc become the final resort. */
+/* */
+/* Misalignment is handled as follows: */
+/* Apad: (AExp>BExp) Swap operands and proceed as for BExp>AExp. */
+/* BPad: Apply the padding by a combination of shifting (whole */
+/* units) and multiplication (part units). */
+/* */
+/* Addition, especially x=x+1, is speed-critical. */
+/* The static buffer is larger than might be expected to allow for */
+/* calls from higher-level funtions (notable exp). */
+/* ------------------------------------------------------------------ */
+static decNumber * decAddOp(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set,
+ uByte negate, uInt *status) {
+ #if DECSUBSET
+ decNumber *alloclhs=NULL; /* non-NULL if rounded lhs allocated */
+ decNumber *allocrhs=NULL; /* .., rhs */
+ #endif
+ Int rhsshift; /* working shift (in Units) */
+ Int maxdigits; /* longest logical length */
+ Int mult; /* multiplier */
+ Int residue; /* rounding accumulator */
+ uByte bits; /* result bits */
+ Flag diffsign; /* non-0 if arguments have different sign */
+ Unit *acc; /* accumulator for result */
+ Unit accbuff[SD2U(DECBUFFER*2+20)]; /* local buffer [*2+20 reduces many */
+ /* allocations when called from */
+ /* other operations, notable exp] */
+ Unit *allocacc=NULL; /* -> allocated acc buffer, iff allocated */
+ Int reqdigits=set->digits; /* local copy; requested DIGITS */
+ Int padding; /* work */
+
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ do { /* protect allocated storage */
+ #if DECSUBSET
+ if (!set->extended) {
+ /* reduce operands and set lostDigits status, as needed */
+ if (lhs->digits>reqdigits) {
+ alloclhs=decRoundOperand(lhs, set, status);
+ if (alloclhs==NULL) break;
+ lhs=alloclhs;
+ }
+ if (rhs->digits>reqdigits) {
+ allocrhs=decRoundOperand(rhs, set, status);
+ if (allocrhs==NULL) break;
+ rhs=allocrhs;
+ }
+ }
+ #endif
+ /* [following code does not require input rounding] */
+
+ /* note whether signs differ [used all paths] */
+ diffsign=(Flag)((lhs->bits^rhs->bits^negate)&DECNEG);
+
+ /* handle infinities and NaNs */
+ if (SPECIALARGS) { /* a special bit set */
+ if (SPECIALARGS & (DECSNAN | DECNAN)) /* a NaN */
+ decNaNs(res, lhs, rhs, set, status);
+ else { /* one or two infinities */
+ if (decNumberIsInfinite(lhs)) { /* LHS is infinity */
+ /* two infinities with different signs is invalid */
+ if (decNumberIsInfinite(rhs) && diffsign) {
+ *status|=DEC_Invalid_operation;
+ break;
+ }
+ bits=lhs->bits & DECNEG; /* get sign from LHS */
+ }
+ else bits=(rhs->bits^negate) & DECNEG;/* RHS must be Infinity */
+ bits|=DECINF;
+ uprv_decNumberZero(res);
+ res->bits=bits; /* set +/- infinity */
+ } /* an infinity */
+ break;
+ }
+
+ /* Quick exit for add 0s; return the non-0, modified as need be */
+ if (ISZERO(lhs)) {
+ Int adjust; /* work */
+ Int lexp=lhs->exponent; /* save in case LHS==RES */
+ bits=lhs->bits; /* .. */
+ residue=0; /* clear accumulator */
+ decCopyFit(res, rhs, set, &residue, status); /* copy (as needed) */
+ res->bits^=negate; /* flip if rhs was negated */
+ #if DECSUBSET
+ if (set->extended) { /* exponents on zeros count */
+ #endif
+ /* exponent will be the lower of the two */
+ adjust=lexp-res->exponent; /* adjustment needed [if -ve] */
+ if (ISZERO(res)) { /* both 0: special IEEE 754 rules */
+ if (adjust<0) res->exponent=lexp; /* set exponent */
+ /* 0-0 gives +0 unless rounding to -infinity, and -0-0 gives -0 */
+ if (diffsign) {
+ if (set->round!=DEC_ROUND_FLOOR) res->bits=0;
+ else res->bits=DECNEG; /* preserve 0 sign */
+ }
+ }
+ else { /* non-0 res */
+ if (adjust<0) { /* 0-padding needed */
+ if ((res->digits-adjust)>set->digits) {
+ adjust=res->digits-set->digits; /* to fit exactly */
+ *status|=DEC_Rounded; /* [but exact] */
+ }
+ res->digits=decShiftToMost(res->lsu, res->digits, -adjust);
+ res->exponent+=adjust; /* set the exponent. */
+ }
+ } /* non-0 res */
+ #if DECSUBSET
+ } /* extended */
+ #endif
+ decFinish(res, set, &residue, status); /* clean and finalize */
+ break;}
+
+ if (ISZERO(rhs)) { /* [lhs is non-zero] */
+ Int adjust; /* work */
+ Int rexp=rhs->exponent; /* save in case RHS==RES */
+ bits=rhs->bits; /* be clean */
+ residue=0; /* clear accumulator */
+ decCopyFit(res, lhs, set, &residue, status); /* copy (as needed) */
+ #if DECSUBSET
+ if (set->extended) { /* exponents on zeros count */
+ #endif
+ /* exponent will be the lower of the two */
+ /* [0-0 case handled above] */
+ adjust=rexp-res->exponent; /* adjustment needed [if -ve] */
+ if (adjust<0) { /* 0-padding needed */
+ if ((res->digits-adjust)>set->digits) {
+ adjust=res->digits-set->digits; /* to fit exactly */
+ *status|=DEC_Rounded; /* [but exact] */
+ }
+ res->digits=decShiftToMost(res->lsu, res->digits, -adjust);
+ res->exponent+=adjust; /* set the exponent. */
+ }
+ #if DECSUBSET
+ } /* extended */
+ #endif
+ decFinish(res, set, &residue, status); /* clean and finalize */
+ break;}
+
+ /* [NB: both fastpath and mainpath code below assume these cases */
+ /* (notably 0-0) have already been handled] */
+
+ /* calculate the padding needed to align the operands */
+ padding=rhs->exponent-lhs->exponent;
+
+ /* Fastpath cases where the numbers are aligned and normal, the RHS */
+ /* is all in one unit, no operand rounding is needed, and no carry, */
+ /* lengthening, or borrow is needed */
+ if (padding==0
+ && rhs->digits<=DECDPUN
+ && rhs->exponent>=set->emin /* [some normals drop through] */
+ && rhs->exponent<=set->emax-set->digits+1 /* [could clamp] */
+ && rhs->digits<=reqdigits
+ && lhs->digits<=reqdigits) {
+ Int partial=*lhs->lsu;
+ if (!diffsign) { /* adding */
+ partial+=*rhs->lsu;
+ if ((partial<=DECDPUNMAX) /* result fits in unit */
+ && (lhs->digits>=DECDPUN || /* .. and no digits-count change */
+ partial<(Int)powers[lhs->digits])) { /* .. */
+ if (res!=lhs) uprv_decNumberCopy(res, lhs); /* not in place */
+ *res->lsu=(Unit)partial; /* [copy could have overwritten RHS] */
+ break;
+ }
+ /* else drop out for careful add */
+ }
+ else { /* signs differ */
+ partial-=*rhs->lsu;
+ if (partial>0) { /* no borrow needed, and non-0 result */
+ if (res!=lhs) uprv_decNumberCopy(res, lhs); /* not in place */
+ *res->lsu=(Unit)partial;
+ /* this could have reduced digits [but result>0] */
+ res->digits=decGetDigits(res->lsu, D2U(res->digits));
+ break;
+ }
+ /* else drop out for careful subtract */
+ }
+ }
+
+ /* Now align (pad) the lhs or rhs so they can be added or */
+ /* subtracted, as necessary. If one number is much larger than */
+ /* the other (that is, if in plain form there is a least one */
+ /* digit between the lowest digit of one and the highest of the */
+ /* other) padding with up to DIGITS-1 trailing zeros may be */
+ /* needed; then apply rounding (as exotic rounding modes may be */
+ /* affected by the residue). */
+ rhsshift=0; /* rhs shift to left (padding) in Units */
+ bits=lhs->bits; /* assume sign is that of LHS */
+ mult=1; /* likely multiplier */
+
+ /* [if padding==0 the operands are aligned; no padding is needed] */
+ if (padding!=0) {
+ /* some padding needed; always pad the RHS, as any required */
+ /* padding can then be effected by a simple combination of */
+ /* shifts and a multiply */
+ Flag swapped=0;
+ if (padding<0) { /* LHS needs the padding */
+ const decNumber *t;
+ padding=-padding; /* will be +ve */
+ bits=(uByte)(rhs->bits^negate); /* assumed sign is now that of RHS */
+ t=lhs; lhs=rhs; rhs=t;
+ swapped=1;
+ }
+
+ /* If, after pad, rhs would be longer than lhs by digits+1 or */
+ /* more then lhs cannot affect the answer, except as a residue, */
+ /* so only need to pad up to a length of DIGITS+1. */
+ if (rhs->digits+padding > lhs->digits+reqdigits+1) {
+ /* The RHS is sufficient */
+ /* for residue use the relative sign indication... */
+ Int shift=reqdigits-rhs->digits; /* left shift needed */
+ residue=1; /* residue for rounding */
+ if (diffsign) residue=-residue; /* signs differ */
+ /* copy, shortening if necessary */
+ decCopyFit(res, rhs, set, &residue, status);
+ /* if it was already shorter, then need to pad with zeros */
+ if (shift>0) {
+ res->digits=decShiftToMost(res->lsu, res->digits, shift);
+ res->exponent-=shift; /* adjust the exponent. */
+ }
+ /* flip the result sign if unswapped and rhs was negated */
+ if (!swapped) res->bits^=negate;
+ decFinish(res, set, &residue, status); /* done */
+ break;}
+
+ /* LHS digits may affect result */
+ rhsshift=D2U(padding+1)-1; /* this much by Unit shift .. */
+ mult=powers[padding-(rhsshift*DECDPUN)]; /* .. this by multiplication */
+ } /* padding needed */
+
+ if (diffsign) mult=-mult; /* signs differ */
+
+ /* determine the longer operand */
+ maxdigits=rhs->digits+padding; /* virtual length of RHS */
+ if (lhs->digits>maxdigits) maxdigits=lhs->digits;
+
+ /* Decide on the result buffer to use; if possible place directly */
+ /* into result. */
+ acc=res->lsu; /* assume add direct to result */
+ /* If destructive overlap, or the number is too long, or a carry or */
+ /* borrow to DIGITS+1 might be possible, a buffer must be used. */
+ /* [Might be worth more sophisticated tests when maxdigits==reqdigits] */
+ if ((maxdigits>=reqdigits) /* is, or could be, too large */
+ || (res==rhs && rhsshift>0)) { /* destructive overlap */
+ /* buffer needed, choose it; units for maxdigits digits will be */
+ /* needed, +1 Unit for carry or borrow */
+ Int need=D2U(maxdigits)+1;
+ acc=accbuff; /* assume use local buffer */
+ if (need*sizeof(Unit)>sizeof(accbuff)) {
+ /* printf("malloc add %ld %ld\n", need, sizeof(accbuff)); */
+ allocacc=(Unit *)malloc(need*sizeof(Unit));
+ if (allocacc==NULL) { /* hopeless -- abandon */
+ *status|=DEC_Insufficient_storage;
+ break;}
+ acc=allocacc;
+ }
+ }
+
+ res->bits=(uByte)(bits&DECNEG); /* it's now safe to overwrite.. */
+ res->exponent=lhs->exponent; /* .. operands (even if aliased) */
+
+ #if DECTRACE
+ decDumpAr('A', lhs->lsu, D2U(lhs->digits));
+ decDumpAr('B', rhs->lsu, D2U(rhs->digits));
+ printf(" :h: %ld %ld\n", rhsshift, mult);
+ #endif
+
+ /* add [A+B*m] or subtract [A+B*(-m)] */
+ U_ASSERT(rhs->digits > 0);
+ U_ASSERT(lhs->digits > 0);
+ res->digits=decUnitAddSub(lhs->lsu, D2U(lhs->digits),
+ rhs->lsu, D2U(rhs->digits),
+ rhsshift, acc, mult)
+ *DECDPUN; /* [units -> digits] */
+ if (res->digits<0) { /* borrowed... */
+ res->digits=-res->digits;
+ res->bits^=DECNEG; /* flip the sign */
+ }
+ #if DECTRACE
+ decDumpAr('+', acc, D2U(res->digits));
+ #endif
+
+ /* If a buffer was used the result must be copied back, possibly */
+ /* shortening. (If no buffer was used then the result must have */
+ /* fit, so can't need rounding and residue must be 0.) */
+ residue=0; /* clear accumulator */
+ if (acc!=res->lsu) {
+ #if DECSUBSET
+ if (set->extended) { /* round from first significant digit */
+ #endif
+ /* remove leading zeros that were added due to rounding up to */
+ /* integral Units -- before the test for rounding. */
+ if (res->digits>reqdigits)
+ res->digits=decGetDigits(acc, D2U(res->digits));
+ decSetCoeff(res, set, acc, res->digits, &residue, status);
+ #if DECSUBSET
+ }
+ else { /* subset arithmetic rounds from original significant digit */
+ /* May have an underestimate. This only occurs when both */
+ /* numbers fit in DECDPUN digits and are padding with a */
+ /* negative multiple (-10, -100...) and the top digit(s) become */
+ /* 0. (This only matters when using X3.274 rules where the */
+ /* leading zero could be included in the rounding.) */
+ if (res->digits<maxdigits) {
+ *(acc+D2U(res->digits))=0; /* ensure leading 0 is there */
+ res->digits=maxdigits;
+ }
+ else {
+ /* remove leading zeros that added due to rounding up to */
+ /* integral Units (but only those in excess of the original */
+ /* maxdigits length, unless extended) before test for rounding. */
+ if (res->digits>reqdigits) {
+ res->digits=decGetDigits(acc, D2U(res->digits));
+ if (res->digits<maxdigits) res->digits=maxdigits;
+ }
+ }
+ decSetCoeff(res, set, acc, res->digits, &residue, status);
+ /* Now apply rounding if needed before removing leading zeros. */
+ /* This is safe because subnormals are not a possibility */
+ if (residue!=0) {
+ decApplyRound(res, set, residue, status);
+ residue=0; /* did what needed to be done */
+ }
+ } /* subset */
+ #endif
+ } /* used buffer */
+
+ /* strip leading zeros [these were left on in case of subset subtract] */
+ res->digits=decGetDigits(res->lsu, D2U(res->digits));
+
+ /* apply checks and rounding */
+ decFinish(res, set, &residue, status);
+
+ /* "When the sum of two operands with opposite signs is exactly */
+ /* zero, the sign of that sum shall be '+' in all rounding modes */
+ /* except round toward -Infinity, in which mode that sign shall be */
+ /* '-'." [Subset zeros also never have '-', set by decFinish.] */
+ if (ISZERO(res) && diffsign
+ #if DECSUBSET
+ && set->extended
+ #endif
+ && (*status&DEC_Inexact)==0) {
+ if (set->round==DEC_ROUND_FLOOR) res->bits|=DECNEG; /* sign - */
+ else res->bits&=~DECNEG; /* sign + */
+ }
+ } while(0); /* end protected */
+
+ if (allocacc!=NULL) free(allocacc); /* drop any storage used */
+ #if DECSUBSET
+ if (allocrhs!=NULL) free(allocrhs); /* .. */
+ if (alloclhs!=NULL) free(alloclhs); /* .. */
+ #endif
+ return res;
+ } /* decAddOp */
+
+/* ------------------------------------------------------------------ */
+/* decDivideOp -- division operation */
+/* */
+/* This routine performs the calculations for all four division */
+/* operators (divide, divideInteger, remainder, remainderNear). */
+/* */
+/* C=A op B */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X/X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* op is DIVIDE, DIVIDEINT, REMAINDER, or REMNEAR respectively. */
+/* status is the usual accumulator */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* ------------------------------------------------------------------ */
+/* The underlying algorithm of this routine is the same as in the */
+/* 1981 S/370 implementation, that is, non-restoring long division */
+/* with bi-unit (rather than bi-digit) estimation for each unit */
+/* multiplier. In this pseudocode overview, complications for the */
+/* Remainder operators and division residues for exact rounding are */
+/* omitted for clarity. */
+/* */
+/* Prepare operands and handle special values */
+/* Test for x/0 and then 0/x */
+/* Exp =Exp1 - Exp2 */
+/* Exp =Exp +len(var1) -len(var2) */
+/* Sign=Sign1 * Sign2 */
+/* Pad accumulator (Var1) to double-length with 0's (pad1) */
+/* Pad Var2 to same length as Var1 */
+/* msu2pair/plus=1st 2 or 1 units of var2, +1 to allow for round */
+/* have=0 */
+/* Do until (have=digits+1 OR residue=0) */
+/* if exp<0 then if integer divide/residue then leave */
+/* this_unit=0 */
+/* Do forever */
+/* compare numbers */
+/* if <0 then leave inner_loop */
+/* if =0 then (* quick exit without subtract *) do */
+/* this_unit=this_unit+1; output this_unit */
+/* leave outer_loop; end */
+/* Compare lengths of numbers (mantissae): */
+/* If same then tops2=msu2pair -- {units 1&2 of var2} */
+/* else tops2=msu2plus -- {0, unit 1 of var2} */
+/* tops1=first_unit_of_Var1*10**DECDPUN +second_unit_of_var1 */
+/* mult=tops1/tops2 -- Good and safe guess at divisor */
+/* if mult=0 then mult=1 */
+/* this_unit=this_unit+mult */
+/* subtract */
+/* end inner_loop */
+/* if have\=0 | this_unit\=0 then do */
+/* output this_unit */
+/* have=have+1; end */
+/* var2=var2/10 */
+/* exp=exp-1 */
+/* end outer_loop */
+/* exp=exp+1 -- set the proper exponent */
+/* if have=0 then generate answer=0 */
+/* Return (Result is defined by Var1) */
+/* */
+/* ------------------------------------------------------------------ */
+/* Two working buffers are needed during the division; one (digits+ */
+/* 1) to accumulate the result, and the other (up to 2*digits+1) for */
+/* long subtractions. These are acc and var1 respectively. */
+/* var1 is a copy of the lhs coefficient, var2 is the rhs coefficient.*/
+/* The static buffers may be larger than might be expected to allow */
+/* for calls from higher-level funtions (notable exp). */
+/* ------------------------------------------------------------------ */
+static decNumber * decDivideOp(decNumber *res,
+ const decNumber *lhs, const decNumber *rhs,
+ decContext *set, Flag op, uInt *status) {
+ #if DECSUBSET
+ decNumber *alloclhs=NULL; /* non-NULL if rounded lhs allocated */
+ decNumber *allocrhs=NULL; /* .., rhs */
+ #endif
+ Unit accbuff[SD2U(DECBUFFER+DECDPUN+10)]; /* local buffer */
+ Unit *acc=accbuff; /* -> accumulator array for result */
+ Unit *allocacc=NULL; /* -> allocated buffer, iff allocated */
+ Unit *accnext; /* -> where next digit will go */
+ Int acclength; /* length of acc needed [Units] */
+ Int accunits; /* count of units accumulated */
+ Int accdigits; /* count of digits accumulated */
+
+ Unit varbuff[SD2U(DECBUFFER*2+DECDPUN)]; /* buffer for var1 */
+ Unit *var1=varbuff; /* -> var1 array for long subtraction */
+ Unit *varalloc=NULL; /* -> allocated buffer, iff used */
+ Unit *msu1; /* -> msu of var1 */
+
+ const Unit *var2; /* -> var2 array */
+ const Unit *msu2; /* -> msu of var2 */
+ Int msu2plus; /* msu2 plus one [does not vary] */
+ eInt msu2pair; /* msu2 pair plus one [does not vary] */
+
+ Int var1units, var2units; /* actual lengths */
+ Int var2ulen; /* logical length (units) */
+ Int var1initpad=0; /* var1 initial padding (digits) */
+ Int maxdigits; /* longest LHS or required acc length */
+ Int mult; /* multiplier for subtraction */
+ Unit thisunit; /* current unit being accumulated */
+ Int residue; /* for rounding */
+ Int reqdigits=set->digits; /* requested DIGITS */
+ Int exponent; /* working exponent */
+ Int maxexponent=0; /* DIVIDE maximum exponent if unrounded */
+ uByte bits; /* working sign */
+ Unit *target; /* work */
+ const Unit *source; /* .. */
+ uInt const *pow; /* .. */
+ Int shift, cut; /* .. */
+ #if DECSUBSET
+ Int dropped; /* work */
+ #endif
+
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ do { /* protect allocated storage */
+ #if DECSUBSET
+ if (!set->extended) {
+ /* reduce operands and set lostDigits status, as needed */
+ if (lhs->digits>reqdigits) {
+ alloclhs=decRoundOperand(lhs, set, status);
+ if (alloclhs==NULL) break;
+ lhs=alloclhs;
+ }
+ if (rhs->digits>reqdigits) {
+ allocrhs=decRoundOperand(rhs, set, status);
+ if (allocrhs==NULL) break;
+ rhs=allocrhs;
+ }
+ }
+ #endif
+ /* [following code does not require input rounding] */
+
+ bits=(lhs->bits^rhs->bits)&DECNEG; /* assumed sign for divisions */
+
+ /* handle infinities and NaNs */
+ if (SPECIALARGS) { /* a special bit set */
+ if (SPECIALARGS & (DECSNAN | DECNAN)) { /* one or two NaNs */
+ decNaNs(res, lhs, rhs, set, status);
+ break;
+ }
+ /* one or two infinities */
+ if (decNumberIsInfinite(lhs)) { /* LHS (dividend) is infinite */
+ if (decNumberIsInfinite(rhs) || /* two infinities are invalid .. */
+ op & (REMAINDER | REMNEAR)) { /* as is remainder of infinity */
+ *status|=DEC_Invalid_operation;
+ break;
+ }
+ /* [Note that infinity/0 raises no exceptions] */
+ uprv_decNumberZero(res);
+ res->bits=bits|DECINF; /* set +/- infinity */
+ break;
+ }
+ else { /* RHS (divisor) is infinite */
+ residue=0;
+ if (op&(REMAINDER|REMNEAR)) {
+ /* result is [finished clone of] lhs */
+ decCopyFit(res, lhs, set, &residue, status);
+ }
+ else { /* a division */
+ uprv_decNumberZero(res);
+ res->bits=bits; /* set +/- zero */
+ /* for DIVIDEINT the exponent is always 0. For DIVIDE, result */
+ /* is a 0 with infinitely negative exponent, clamped to minimum */
+ if (op&DIVIDE) {
+ res->exponent=set->emin-set->digits+1;
+ *status|=DEC_Clamped;
+ }
+ }
+ decFinish(res, set, &residue, status);
+ break;
+ }
+ }
+
+ /* handle 0 rhs (x/0) */
+ if (ISZERO(rhs)) { /* x/0 is always exceptional */
+ if (ISZERO(lhs)) {
+ uprv_decNumberZero(res); /* [after lhs test] */
+ *status|=DEC_Division_undefined;/* 0/0 will become NaN */
+ }
+ else {
+ uprv_decNumberZero(res);
+ if (op&(REMAINDER|REMNEAR)) *status|=DEC_Invalid_operation;
+ else {
+ *status|=DEC_Division_by_zero; /* x/0 */
+ res->bits=bits|DECINF; /* .. is +/- Infinity */
+ }
+ }
+ break;}
+
+ /* handle 0 lhs (0/x) */
+ if (ISZERO(lhs)) { /* 0/x [x!=0] */
+ #if DECSUBSET
+ if (!set->extended) uprv_decNumberZero(res);
+ else {
+ #endif
+ if (op&DIVIDE) {
+ residue=0;
+ exponent=lhs->exponent-rhs->exponent; /* ideal exponent */
+ uprv_decNumberCopy(res, lhs); /* [zeros always fit] */
+ res->bits=bits; /* sign as computed */
+ res->exponent=exponent; /* exponent, too */
+ decFinalize(res, set, &residue, status); /* check exponent */
+ }
+ else if (op&DIVIDEINT) {
+ uprv_decNumberZero(res); /* integer 0 */
+ res->bits=bits; /* sign as computed */
+ }
+ else { /* a remainder */
+ exponent=rhs->exponent; /* [save in case overwrite] */
+ uprv_decNumberCopy(res, lhs); /* [zeros always fit] */
+ if (exponent<res->exponent) res->exponent=exponent; /* use lower */
+ }
+ #if DECSUBSET
+ }
+ #endif
+ break;}
+
+ /* Precalculate exponent. This starts off adjusted (and hence fits */
+ /* in 31 bits) and becomes the usual unadjusted exponent as the */
+ /* division proceeds. The order of evaluation is important, here, */
+ /* to avoid wrap. */
+ exponent=(lhs->exponent+lhs->digits)-(rhs->exponent+rhs->digits);
+
+ /* If the working exponent is -ve, then some quick exits are */
+ /* possible because the quotient is known to be <1 */
+ /* [for REMNEAR, it needs to be < -1, as -0.5 could need work] */
+ if (exponent<0 && !(op==DIVIDE)) {
+ if (op&DIVIDEINT) {
+ uprv_decNumberZero(res); /* integer part is 0 */
+ #if DECSUBSET
+ if (set->extended)
+ #endif
+ res->bits=bits; /* set +/- zero */
+ break;}
+ /* fastpath remainders so long as the lhs has the smaller */
+ /* (or equal) exponent */
+ if (lhs->exponent<=rhs->exponent) {
+ if (op&REMAINDER || exponent<-1) {
+ /* It is REMAINDER or safe REMNEAR; result is [finished */
+ /* clone of] lhs (r = x - 0*y) */
+ residue=0;
+ decCopyFit(res, lhs, set, &residue, status);
+ decFinish(res, set, &residue, status);
+ break;
+ }
+ /* [unsafe REMNEAR drops through] */
+ }
+ } /* fastpaths */
+
+ /* Long (slow) division is needed; roll up the sleeves... */
+
+ /* The accumulator will hold the quotient of the division. */
+ /* If it needs to be too long for stack storage, then allocate. */
+ acclength=D2U(reqdigits+DECDPUN); /* in Units */
+ if (acclength*sizeof(Unit)>sizeof(accbuff)) {
+ /* printf("malloc dvacc %ld units\n", acclength); */
+ allocacc=(Unit *)malloc(acclength*sizeof(Unit));
+ if (allocacc==NULL) { /* hopeless -- abandon */
+ *status|=DEC_Insufficient_storage;
+ break;}
+ acc=allocacc; /* use the allocated space */
+ }
+
+ /* var1 is the padded LHS ready for subtractions. */
+ /* If it needs to be too long for stack storage, then allocate. */
+ /* The maximum units needed for var1 (long subtraction) is: */
+ /* Enough for */
+ /* (rhs->digits+reqdigits-1) -- to allow full slide to right */
+ /* or (lhs->digits) -- to allow for long lhs */
+ /* whichever is larger */
+ /* +1 -- for rounding of slide to right */
+ /* +1 -- for leading 0s */
+ /* +1 -- for pre-adjust if a remainder or DIVIDEINT */
+ /* [Note: unused units do not participate in decUnitAddSub data] */
+ maxdigits=rhs->digits+reqdigits-1;
+ if (lhs->digits>maxdigits) maxdigits=lhs->digits;
+ var1units=D2U(maxdigits)+2;
+ /* allocate a guard unit above msu1 for REMAINDERNEAR */
+ if (!(op&DIVIDE)) var1units++;
+ if ((var1units+1)*sizeof(Unit)>sizeof(varbuff)) {
+ /* printf("malloc dvvar %ld units\n", var1units+1); */
+ varalloc=(Unit *)malloc((var1units+1)*sizeof(Unit));
+ if (varalloc==NULL) { /* hopeless -- abandon */
+ *status|=DEC_Insufficient_storage;
+ break;}
+ var1=varalloc; /* use the allocated space */
+ }
+
+ /* Extend the lhs and rhs to full long subtraction length. The lhs */
+ /* is truly extended into the var1 buffer, with 0 padding, so a */
+ /* subtract in place is always possible. The rhs (var2) has */
+ /* virtual padding (implemented by decUnitAddSub). */
+ /* One guard unit was allocated above msu1 for rem=rem+rem in */
+ /* REMAINDERNEAR. */
+ msu1=var1+var1units-1; /* msu of var1 */
+ source=lhs->lsu+D2U(lhs->digits)-1; /* msu of input array */
+ for (target=msu1; source>=lhs->lsu; source--, target--) *target=*source;
+ for (; target>=var1; target--) *target=0;
+
+ /* rhs (var2) is left-aligned with var1 at the start */
+ var2ulen=var1units; /* rhs logical length (units) */
+ var2units=D2U(rhs->digits); /* rhs actual length (units) */
+ var2=rhs->lsu; /* -> rhs array */
+ msu2=var2+var2units-1; /* -> msu of var2 [never changes] */
+ /* now set up the variables which will be used for estimating the */
+ /* multiplication factor. If these variables are not exact, add */
+ /* 1 to make sure that the multiplier is never overestimated. */
+ msu2plus=*msu2; /* it's value .. */
+ if (var2units>1) msu2plus++; /* .. +1 if any more */
+ msu2pair=(eInt)*msu2*(DECDPUNMAX+1);/* top two pair .. */
+ if (var2units>1) { /* .. [else treat 2nd as 0] */
+ msu2pair+=*(msu2-1); /* .. */
+ if (var2units>2) msu2pair++; /* .. +1 if any more */
+ }
+
+ /* The calculation is working in units, which may have leading zeros, */
+ /* but the exponent was calculated on the assumption that they are */
+ /* both left-aligned. Adjust the exponent to compensate: add the */
+ /* number of leading zeros in var1 msu and subtract those in var2 msu. */
+ /* [This is actually done by counting the digits and negating, as */
+ /* lead1=DECDPUN-digits1, and similarly for lead2.] */
+ for (pow=&powers[1]; *msu1>=*pow; pow++) exponent--;
+ for (pow=&powers[1]; *msu2>=*pow; pow++) exponent++;
+
+ /* Now, if doing an integer divide or remainder, ensure that */
+ /* the result will be Unit-aligned. To do this, shift the var1 */
+ /* accumulator towards least if need be. (It's much easier to */
+ /* do this now than to reassemble the residue afterwards, if */
+ /* doing a remainder.) Also ensure the exponent is not negative. */
+ if (!(op&DIVIDE)) {
+ Unit *u; /* work */
+ /* save the initial 'false' padding of var1, in digits */
+ var1initpad=(var1units-D2U(lhs->digits))*DECDPUN;
+ /* Determine the shift to do. */
+ if (exponent<0) cut=-exponent;
+ else cut=DECDPUN-exponent%DECDPUN;
+ decShiftToLeast(var1, var1units, cut);
+ exponent+=cut; /* maintain numerical value */
+ var1initpad-=cut; /* .. and reduce padding */
+ /* clean any most-significant units which were just emptied */
+ for (u=msu1; cut>=DECDPUN; cut-=DECDPUN, u--) *u=0;
+ } /* align */
+ else { /* is DIVIDE */
+ maxexponent=lhs->exponent-rhs->exponent; /* save */
+ /* optimization: if the first iteration will just produce 0, */
+ /* preadjust to skip it [valid for DIVIDE only] */
+ if (*msu1<*msu2) {
+ var2ulen--; /* shift down */
+ exponent-=DECDPUN; /* update the exponent */
+ }
+ }
+
+ /* ---- start the long-division loops ------------------------------ */
+ accunits=0; /* no units accumulated yet */
+ accdigits=0; /* .. or digits */
+ accnext=acc+acclength-1; /* -> msu of acc [NB: allows digits+1] */
+ for (;;) { /* outer forever loop */
+ thisunit=0; /* current unit assumed 0 */
+ /* find the next unit */
+ for (;;) { /* inner forever loop */
+ /* strip leading zero units [from either pre-adjust or from */
+ /* subtract last time around]. Leave at least one unit. */
+ for (; *msu1==0 && msu1>var1; msu1--) var1units--;
+
+ if (var1units<var2ulen) break; /* var1 too low for subtract */
+ if (var1units==var2ulen) { /* unit-by-unit compare needed */
+ /* compare the two numbers, from msu */
+ const Unit *pv1, *pv2;
+ Unit v2; /* units to compare */
+ pv2=msu2; /* -> msu */
+ for (pv1=msu1; ; pv1--, pv2--) {
+ /* v1=*pv1 -- always OK */
+ v2=0; /* assume in padding */
+ if (pv2>=var2) v2=*pv2; /* in range */
+ if (*pv1!=v2) break; /* no longer the same */
+ if (pv1==var1) break; /* done; leave pv1 as is */
+ }
+ /* here when all inspected or a difference seen */
+ if (*pv1<v2) break; /* var1 too low to subtract */
+ if (*pv1==v2) { /* var1 == var2 */
+ /* reach here if var1 and var2 are identical; subtraction */
+ /* would increase digit by one, and the residue will be 0 so */
+ /* the calculation is done; leave the loop with residue=0. */
+ thisunit++; /* as though subtracted */
+ *var1=0; /* set var1 to 0 */
+ var1units=1; /* .. */
+ break; /* from inner */
+ } /* var1 == var2 */
+ /* *pv1>v2. Prepare for real subtraction; the lengths are equal */
+ /* Estimate the multiplier (there's always a msu1-1)... */
+ /* Bring in two units of var2 to provide a good estimate. */
+ mult=(Int)(((eInt)*msu1*(DECDPUNMAX+1)+*(msu1-1))/msu2pair);
+ } /* lengths the same */
+ else { /* var1units > var2ulen, so subtraction is safe */
+ /* The var2 msu is one unit towards the lsu of the var1 msu, */
+ /* so only one unit for var2 can be used. */
+ mult=(Int)(((eInt)*msu1*(DECDPUNMAX+1)+*(msu1-1))/msu2plus);
+ }
+ if (mult==0) mult=1; /* must always be at least 1 */
+ /* subtraction needed; var1 is > var2 */
+ thisunit=(Unit)(thisunit+mult); /* accumulate */
+ /* subtract var1-var2, into var1; only the overlap needs */
+ /* processing, as this is an in-place calculation */
+ shift=var2ulen-var2units;
+ #if DECTRACE
+ decDumpAr('1', &var1[shift], var1units-shift);
+ decDumpAr('2', var2, var2units);
+ printf("m=%ld\n", -mult);
+ #endif
+ decUnitAddSub(&var1[shift], var1units-shift,
+ var2, var2units, 0,
+ &var1[shift], -mult);
+ #if DECTRACE
+ decDumpAr('#', &var1[shift], var1units-shift);
+ #endif
+ /* var1 now probably has leading zeros; these are removed at the */
+ /* top of the inner loop. */
+ } /* inner loop */
+
+ /* The next unit has been calculated in full; unless it's a */
+ /* leading zero, add to acc */
+ if (accunits!=0 || thisunit!=0) { /* is first or non-zero */
+ *accnext=thisunit; /* store in accumulator */
+ /* account exactly for the new digits */
+ if (accunits==0) {
+ accdigits++; /* at least one */
+ for (pow=&powers[1]; thisunit>=*pow; pow++) accdigits++;
+ }
+ else accdigits+=DECDPUN;
+ accunits++; /* update count */
+ accnext--; /* ready for next */
+ if (accdigits>reqdigits) break; /* have enough digits */
+ }
+
+ /* if the residue is zero, the operation is done (unless divide */
+ /* or divideInteger and still not enough digits yet) */
+ if (*var1==0 && var1units==1) { /* residue is 0 */
+ if (op&(REMAINDER|REMNEAR)) break;
+ if ((op&DIVIDE) && (exponent<=maxexponent)) break;
+ /* [drop through if divideInteger] */
+ }
+ /* also done enough if calculating remainder or integer */
+ /* divide and just did the last ('units') unit */
+ if (exponent==0 && !(op&DIVIDE)) break;
+
+ /* to get here, var1 is less than var2, so divide var2 by the per- */
+ /* Unit power of ten and go for the next digit */
+ var2ulen--; /* shift down */
+ exponent-=DECDPUN; /* update the exponent */
+ } /* outer loop */
+
+ /* ---- division is complete --------------------------------------- */
+ /* here: acc has at least reqdigits+1 of good results (or fewer */
+ /* if early stop), starting at accnext+1 (its lsu) */
+ /* var1 has any residue at the stopping point */
+ /* accunits is the number of digits collected in acc */
+ if (accunits==0) { /* acc is 0 */
+ accunits=1; /* show have a unit .. */
+ accdigits=1; /* .. */
+ *accnext=0; /* .. whose value is 0 */
+ }
+ else accnext++; /* back to last placed */
+ /* accnext now -> lowest unit of result */
+
+ residue=0; /* assume no residue */
+ if (op&DIVIDE) {
+ /* record the presence of any residue, for rounding */
+ if (*var1!=0 || var1units>1) residue=1;
+ else { /* no residue */
+ /* Had an exact division; clean up spurious trailing 0s. */
+ /* There will be at most DECDPUN-1, from the final multiply, */
+ /* and then only if the result is non-0 (and even) and the */
+ /* exponent is 'loose'. */
+ #if DECDPUN>1
+ Unit lsu=*accnext;
+ if (!(lsu&0x01) && (lsu!=0)) {
+ /* count the trailing zeros */
+ Int drop=0;
+ for (;; drop++) { /* [will terminate because lsu!=0] */
+ if (exponent>=maxexponent) break; /* don't chop real 0s */
+ #if DECDPUN<=4
+ if ((lsu-QUOT10(lsu, drop+1)
+ *powers[drop+1])!=0) break; /* found non-0 digit */
+ #else
+ if (lsu%powers[drop+1]!=0) break; /* found non-0 digit */
+ #endif
+ exponent++;
+ }
+ if (drop>0) {
+ accunits=decShiftToLeast(accnext, accunits, drop);
+ accdigits=decGetDigits(accnext, accunits);
+ accunits=D2U(accdigits);
+ /* [exponent was adjusted in the loop] */
+ }
+ } /* neither odd nor 0 */
+ #endif
+ } /* exact divide */
+ } /* divide */
+ else /* op!=DIVIDE */ {
+ /* check for coefficient overflow */
+ if (accdigits+exponent>reqdigits) {
+ *status|=DEC_Division_impossible;
+ break;
+ }
+ if (op & (REMAINDER|REMNEAR)) {
+ /* [Here, the exponent will be 0, because var1 was adjusted */
+ /* appropriately.] */
+ Int postshift; /* work */
+ Flag wasodd=0; /* integer was odd */
+ Unit *quotlsu; /* for save */
+ Int quotdigits; /* .. */
+
+ bits=lhs->bits; /* remainder sign is always as lhs */
+
+ /* Fastpath when residue is truly 0 is worthwhile [and */
+ /* simplifies the code below] */
+ if (*var1==0 && var1units==1) { /* residue is 0 */
+ Int exp=lhs->exponent; /* save min(exponents) */
+ if (rhs->exponent<exp) exp=rhs->exponent;
+ uprv_decNumberZero(res); /* 0 coefficient */
+ #if DECSUBSET
+ if (set->extended)
+ #endif
+ res->exponent=exp; /* .. with proper exponent */
+ res->bits=(uByte)(bits&DECNEG); /* [cleaned] */
+ decFinish(res, set, &residue, status); /* might clamp */
+ break;
+ }
+ /* note if the quotient was odd */
+ if (*accnext & 0x01) wasodd=1; /* acc is odd */
+ quotlsu=accnext; /* save in case need to reinspect */
+ quotdigits=accdigits; /* .. */
+
+ /* treat the residue, in var1, as the value to return, via acc */
+ /* calculate the unused zero digits. This is the smaller of: */
+ /* var1 initial padding (saved above) */
+ /* var2 residual padding, which happens to be given by: */
+ postshift=var1initpad+exponent-lhs->exponent+rhs->exponent;
+ /* [the 'exponent' term accounts for the shifts during divide] */
+ if (var1initpad<postshift) postshift=var1initpad;
+
+ /* shift var1 the requested amount, and adjust its digits */
+ var1units=decShiftToLeast(var1, var1units, postshift);
+ accnext=var1;
+ accdigits=decGetDigits(var1, var1units);
+ accunits=D2U(accdigits);
+
+ exponent=lhs->exponent; /* exponent is smaller of lhs & rhs */
+ if (rhs->exponent<exponent) exponent=rhs->exponent;
+
+ /* Now correct the result if doing remainderNear; if it */
+ /* (looking just at coefficients) is > rhs/2, or == rhs/2 and */
+ /* the integer was odd then the result should be rem-rhs. */
+ if (op&REMNEAR) {
+ Int compare, tarunits; /* work */
+ Unit *up; /* .. */
+ /* calculate remainder*2 into the var1 buffer (which has */
+ /* 'headroom' of an extra unit and hence enough space) */
+ /* [a dedicated 'double' loop would be faster, here] */
+ tarunits=decUnitAddSub(accnext, accunits, accnext, accunits,
+ 0, accnext, 1);
+ /* decDumpAr('r', accnext, tarunits); */
+
+ /* Here, accnext (var1) holds tarunits Units with twice the */
+ /* remainder's coefficient, which must now be compared to the */
+ /* RHS. The remainder's exponent may be smaller than the RHS's. */
+ compare=decUnitCompare(accnext, tarunits, rhs->lsu, D2U(rhs->digits),
+ rhs->exponent-exponent);
+ if (compare==BADINT) { /* deep trouble */
+ *status|=DEC_Insufficient_storage;
+ break;}
+
+ /* now restore the remainder by dividing by two; the lsu */
+ /* is known to be even. */
+ for (up=accnext; up<accnext+tarunits; up++) {
+ Int half; /* half to add to lower unit */
+ half=*up & 0x01;
+ *up/=2; /* [shift] */
+ if (!half) continue;
+ *(up-1)+=(DECDPUNMAX+1)/2;
+ }
+ /* [accunits still describes the original remainder length] */
+
+ if (compare>0 || (compare==0 && wasodd)) { /* adjustment needed */
+ Int exp, expunits, exprem; /* work */
+ /* This is effectively causing round-up of the quotient, */
+ /* so if it was the rare case where it was full and all */
+ /* nines, it would overflow and hence division-impossible */
+ /* should be raised */
+ Flag allnines=0; /* 1 if quotient all nines */
+ if (quotdigits==reqdigits) { /* could be borderline */
+ for (up=quotlsu; ; up++) {
+ if (quotdigits>DECDPUN) {
+ if (*up!=DECDPUNMAX) break;/* non-nines */
+ }
+ else { /* this is the last Unit */
+ if (*up==powers[quotdigits]-1) allnines=1;
+ break;
+ }
+ quotdigits-=DECDPUN; /* checked those digits */
+ } /* up */
+ } /* borderline check */
+ if (allnines) {
+ *status|=DEC_Division_impossible;
+ break;}
+
+ /* rem-rhs is needed; the sign will invert. Again, var1 */
+ /* can safely be used for the working Units array. */
+ exp=rhs->exponent-exponent; /* RHS padding needed */
+ /* Calculate units and remainder from exponent. */
+ expunits=exp/DECDPUN;
+ exprem=exp%DECDPUN;
+ /* subtract [A+B*(-m)]; the result will always be negative */
+ accunits=-decUnitAddSub(accnext, accunits,
+ rhs->lsu, D2U(rhs->digits),
+ expunits, accnext, -(Int)powers[exprem]);
+ accdigits=decGetDigits(accnext, accunits); /* count digits exactly */
+ accunits=D2U(accdigits); /* and recalculate the units for copy */
+ /* [exponent is as for original remainder] */
+ bits^=DECNEG; /* flip the sign */
+ }
+ } /* REMNEAR */
+ } /* REMAINDER or REMNEAR */
+ } /* not DIVIDE */
+
+ /* Set exponent and bits */
+ res->exponent=exponent;
+ res->bits=(uByte)(bits&DECNEG); /* [cleaned] */
+
+ /* Now the coefficient. */
+ decSetCoeff(res, set, accnext, accdigits, &residue, status);
+
+ decFinish(res, set, &residue, status); /* final cleanup */
+
+ #if DECSUBSET
+ /* If a divide then strip trailing zeros if subset [after round] */
+ if (!set->extended && (op==DIVIDE)) decTrim(res, set, 0, 1, &dropped);
+ #endif
+ } while(0); /* end protected */
+
+ if (varalloc!=NULL) free(varalloc); /* drop any storage used */
+ if (allocacc!=NULL) free(allocacc); /* .. */
+ #if DECSUBSET
+ if (allocrhs!=NULL) free(allocrhs); /* .. */
+ if (alloclhs!=NULL) free(alloclhs); /* .. */
+ #endif
+ return res;
+ } /* decDivideOp */
+
+/* ------------------------------------------------------------------ */
+/* decMultiplyOp -- multiplication operation */
+/* */
+/* This routine performs the multiplication C=A x B. */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X*X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* status is the usual accumulator */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* ------------------------------------------------------------------ */
+/* 'Classic' multiplication is used rather than Karatsuba, as the */
+/* latter would give only a minor improvement for the short numbers */
+/* expected to be handled most (and uses much more memory). */
+/* */
+/* There are two major paths here: the general-purpose ('old code') */
+/* path which handles all DECDPUN values, and a fastpath version */
+/* which is used if 64-bit ints are available, DECDPUN<=4, and more */
+/* than two calls to decUnitAddSub would be made. */
+/* */
+/* The fastpath version lumps units together into 8-digit or 9-digit */
+/* chunks, and also uses a lazy carry strategy to minimise expensive */
+/* 64-bit divisions. The chunks are then broken apart again into */
+/* units for continuing processing. Despite this overhead, the */
+/* fastpath can speed up some 16-digit operations by 10x (and much */
+/* more for higher-precision calculations). */
+/* */
+/* A buffer always has to be used for the accumulator; in the */
+/* fastpath, buffers are also always needed for the chunked copies of */
+/* of the operand coefficients. */
+/* Static buffers are larger than needed just for multiply, to allow */
+/* for calls from other operations (notably exp). */
+/* ------------------------------------------------------------------ */
+#define FASTMUL (DECUSE64 && DECDPUN<5)
+static decNumber * decMultiplyOp(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set,
+ uInt *status) {
+ Int accunits; /* Units of accumulator in use */
+ Int exponent; /* work */
+ Int residue=0; /* rounding residue */
+ uByte bits; /* result sign */
+ Unit *acc; /* -> accumulator Unit array */
+ Int needbytes; /* size calculator */
+ void *allocacc=NULL; /* -> allocated accumulator, iff allocated */
+ Unit accbuff[SD2U(DECBUFFER*4+1)]; /* buffer (+1 for DECBUFFER==0, */
+ /* *4 for calls from other operations) */
+ const Unit *mer, *mermsup; /* work */
+ Int madlength; /* Units in multiplicand */
+ Int shift; /* Units to shift multiplicand by */
+
+ #if FASTMUL
+ /* if DECDPUN is 1 or 3 work in base 10**9, otherwise */
+ /* (DECDPUN is 2 or 4) then work in base 10**8 */
+ #if DECDPUN & 1 /* odd */
+ #define FASTBASE 1000000000 /* base */
+ #define FASTDIGS 9 /* digits in base */
+ #define FASTLAZY 18 /* carry resolution point [1->18] */
+ #else
+ #define FASTBASE 100000000
+ #define FASTDIGS 8
+ #define FASTLAZY 1844 /* carry resolution point [1->1844] */
+ #endif
+ /* three buffers are used, two for chunked copies of the operands */
+ /* (base 10**8 or base 10**9) and one base 2**64 accumulator with */
+ /* lazy carry evaluation */
+ uInt zlhibuff[(DECBUFFER*2+1)/8+1]; /* buffer (+1 for DECBUFFER==0) */
+ uInt *zlhi=zlhibuff; /* -> lhs array */
+ uInt *alloclhi=NULL; /* -> allocated buffer, iff allocated */
+ uInt zrhibuff[(DECBUFFER*2+1)/8+1]; /* buffer (+1 for DECBUFFER==0) */
+ uInt *zrhi=zrhibuff; /* -> rhs array */
+ uInt *allocrhi=NULL; /* -> allocated buffer, iff allocated */
+ uLong zaccbuff[(DECBUFFER*2+1)/4+2]; /* buffer (+1 for DECBUFFER==0) */
+ /* [allocacc is shared for both paths, as only one will run] */
+ uLong *zacc=zaccbuff; /* -> accumulator array for exact result */
+ #if DECDPUN==1
+ Int zoff; /* accumulator offset */
+ #endif
+ uInt *lip, *rip; /* item pointers */
+ uInt *lmsi, *rmsi; /* most significant items */
+ Int ilhs, irhs, iacc; /* item counts in the arrays */
+ Int lazy; /* lazy carry counter */
+ uLong lcarry; /* uLong carry */
+ uInt carry; /* carry (NB not uLong) */
+ Int count; /* work */
+ const Unit *cup; /* .. */
+ Unit *up; /* .. */
+ uLong *lp; /* .. */
+ Int p; /* .. */
+ #endif
+
+ #if DECSUBSET
+ decNumber *alloclhs=NULL; /* -> allocated buffer, iff allocated */
+ decNumber *allocrhs=NULL; /* -> allocated buffer, iff allocated */
+ #endif
+
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ /* precalculate result sign */
+ bits=(uByte)((lhs->bits^rhs->bits)&DECNEG);
+
+ /* handle infinities and NaNs */
+ if (SPECIALARGS) { /* a special bit set */
+ if (SPECIALARGS & (DECSNAN | DECNAN)) { /* one or two NaNs */
+ decNaNs(res, lhs, rhs, set, status);
+ return res;}
+ /* one or two infinities; Infinity * 0 is invalid */
+ if (((lhs->bits & DECINF)==0 && ISZERO(lhs))
+ ||((rhs->bits & DECINF)==0 && ISZERO(rhs))) {
+ *status|=DEC_Invalid_operation;
+ return res;}
+ uprv_decNumberZero(res);
+ res->bits=bits|DECINF; /* infinity */
+ return res;}
+
+ /* For best speed, as in DMSRCN [the original Rexx numerics */
+ /* module], use the shorter number as the multiplier (rhs) and */
+ /* the longer as the multiplicand (lhs) to minimise the number of */
+ /* adds (partial products) */
+ if (lhs->digits<rhs->digits) { /* swap... */
+ const decNumber *hold=lhs;
+ lhs=rhs;
+ rhs=hold;
+ }
+
+ do { /* protect allocated storage */
+ #if DECSUBSET
+ if (!set->extended) {
+ /* reduce operands and set lostDigits status, as needed */
+ if (lhs->digits>set->digits) {
+ alloclhs=decRoundOperand(lhs, set, status);
+ if (alloclhs==NULL) break;
+ lhs=alloclhs;
+ }
+ if (rhs->digits>set->digits) {
+ allocrhs=decRoundOperand(rhs, set, status);
+ if (allocrhs==NULL) break;
+ rhs=allocrhs;
+ }
+ }
+ #endif
+ /* [following code does not require input rounding] */
+
+ #if FASTMUL /* fastpath can be used */
+ /* use the fast path if there are enough digits in the shorter */
+ /* operand to make the setup and takedown worthwhile */
+ #define NEEDTWO (DECDPUN*2) /* within two decUnitAddSub calls */
+ if (rhs->digits>NEEDTWO) { /* use fastpath... */
+ /* calculate the number of elements in each array */
+ ilhs=(lhs->digits+FASTDIGS-1)/FASTDIGS; /* [ceiling] */
+ irhs=(rhs->digits+FASTDIGS-1)/FASTDIGS; /* .. */
+ iacc=ilhs+irhs;
+
+ /* allocate buffers if required, as usual */
+ needbytes=ilhs*sizeof(uInt);
+ if (needbytes>(Int)sizeof(zlhibuff)) {
+ alloclhi=(uInt *)malloc(needbytes);
+ zlhi=alloclhi;}
+ needbytes=irhs*sizeof(uInt);
+ if (needbytes>(Int)sizeof(zrhibuff)) {
+ allocrhi=(uInt *)malloc(needbytes);
+ zrhi=allocrhi;}
+
+ /* Allocating the accumulator space needs a special case when */
+ /* DECDPUN=1 because when converting the accumulator to Units */
+ /* after the multiplication each 8-byte item becomes 9 1-byte */
+ /* units. Therefore iacc extra bytes are needed at the front */
+ /* (rounded up to a multiple of 8 bytes), and the uLong */
+ /* accumulator starts offset the appropriate number of units */
+ /* to the right to avoid overwrite during the unchunking. */
+
+ /* Make sure no signed int overflow below. This is always true */
+ /* if the given numbers have less digits than DEC_MAX_DIGITS. */
+ U_ASSERT((uint32_t)iacc <= INT32_MAX/sizeof(uLong));
+ needbytes=iacc*sizeof(uLong);
+ #if DECDPUN==1
+ zoff=(iacc+7)/8; /* items to offset by */
+ needbytes+=zoff*8;
+ #endif
+ if (needbytes>(Int)sizeof(zaccbuff)) {
+ allocacc=(uLong *)malloc(needbytes);
+ zacc=(uLong *)allocacc;}
+ if (zlhi==NULL||zrhi==NULL||zacc==NULL) {
+ *status|=DEC_Insufficient_storage;
+ break;}
+
+ acc=(Unit *)zacc; /* -> target Unit array */
+ #if DECDPUN==1
+ zacc+=zoff; /* start uLong accumulator to right */
+ #endif
+
+ /* assemble the chunked copies of the left and right sides */
+ for (count=lhs->digits, cup=lhs->lsu, lip=zlhi; count>0; lip++)
+ for (p=0, *lip=0; p<FASTDIGS && count>0;
+ p+=DECDPUN, cup++, count-=DECDPUN)
+ *lip+=*cup*powers[p];
+ lmsi=lip-1; /* save -> msi */
+ for (count=rhs->digits, cup=rhs->lsu, rip=zrhi; count>0; rip++)
+ for (p=0, *rip=0; p<FASTDIGS && count>0;
+ p+=DECDPUN, cup++, count-=DECDPUN)
+ *rip+=*cup*powers[p];
+ rmsi=rip-1; /* save -> msi */
+
+ /* zero the accumulator */
+ for (lp=zacc; lp<zacc+iacc; lp++) *lp=0;
+
+ /* Start the multiplication */
+ /* Resolving carries can dominate the cost of accumulating the */
+ /* partial products, so this is only done when necessary. */
+ /* Each uLong item in the accumulator can hold values up to */
+ /* 2**64-1, and each partial product can be as large as */
+ /* (10**FASTDIGS-1)**2. When FASTDIGS=9, this can be added to */
+ /* itself 18.4 times in a uLong without overflowing, so during */
+ /* the main calculation resolution is carried out every 18th */
+ /* add -- every 162 digits. Similarly, when FASTDIGS=8, the */
+ /* partial products can be added to themselves 1844.6 times in */
+ /* a uLong without overflowing, so intermediate carry */
+ /* resolution occurs only every 14752 digits. Hence for common */
+ /* short numbers usually only the one final carry resolution */
+ /* occurs. */
+ /* (The count is set via FASTLAZY to simplify experiments to */
+ /* measure the value of this approach: a 35% improvement on a */
+ /* [34x34] multiply.) */
+ lazy=FASTLAZY; /* carry delay count */
+ for (rip=zrhi; rip<=rmsi; rip++) { /* over each item in rhs */
+ lp=zacc+(rip-zrhi); /* where to add the lhs */
+ for (lip=zlhi; lip<=lmsi; lip++, lp++) { /* over each item in lhs */
+ *lp+=(uLong)(*lip)*(*rip); /* [this should in-line] */
+ } /* lip loop */
+ lazy--;
+ if (lazy>0 && rip!=rmsi) continue;
+ lazy=FASTLAZY; /* reset delay count */
+ /* spin up the accumulator resolving overflows */
+ for (lp=zacc; lp<zacc+iacc; lp++) {
+ if (*lp<FASTBASE) continue; /* it fits */
+ lcarry=*lp/FASTBASE; /* top part [slow divide] */
+ /* lcarry can exceed 2**32-1, so check again; this check */
+ /* and occasional extra divide (slow) is well worth it, as */
+ /* it allows FASTLAZY to be increased to 18 rather than 4 */
+ /* in the FASTDIGS=9 case */
+ if (lcarry<FASTBASE) carry=(uInt)lcarry; /* [usual] */
+ else { /* two-place carry [fairly rare] */
+ uInt carry2=(uInt)(lcarry/FASTBASE); /* top top part */
+ *(lp+2)+=carry2; /* add to item+2 */
+ *lp-=((uLong)FASTBASE*FASTBASE*carry2); /* [slow] */
+ carry=(uInt)(lcarry-((uLong)FASTBASE*carry2)); /* [inline] */
+ }
+ *(lp+1)+=carry; /* add to item above [inline] */
+ *lp-=((uLong)FASTBASE*carry); /* [inline] */
+ } /* carry resolution */
+ } /* rip loop */
+
+ /* The multiplication is complete; time to convert back into */
+ /* units. This can be done in-place in the accumulator and in */
+ /* 32-bit operations, because carries were resolved after the */
+ /* final add. This needs N-1 divides and multiplies for */
+ /* each item in the accumulator (which will become up to N */
+ /* units, where 2<=N<=9). */
+ for (lp=zacc, up=acc; lp<zacc+iacc; lp++) {
+ uInt item=(uInt)*lp; /* decapitate to uInt */
+ for (p=0; p<FASTDIGS-DECDPUN; p+=DECDPUN, up++) {
+ uInt part=item/(DECDPUNMAX+1);
+ *up=(Unit)(item-(part*(DECDPUNMAX+1)));
+ item=part;
+ } /* p */
+ *up=(Unit)item; up++; /* [final needs no division] */
+ } /* lp */
+ accunits = static_cast<int32_t>(up-acc); /* count of units */
+ }
+ else { /* here to use units directly, without chunking ['old code'] */
+ #endif
+
+ /* if accumulator will be too long for local storage, then allocate */
+ acc=accbuff; /* -> assume buffer for accumulator */
+ needbytes=(D2U(lhs->digits)+D2U(rhs->digits))*sizeof(Unit);
+ if (needbytes>(Int)sizeof(accbuff)) {
+ allocacc=(Unit *)malloc(needbytes);
+ if (allocacc==NULL) {*status|=DEC_Insufficient_storage; break;}
+ acc=(Unit *)allocacc; /* use the allocated space */
+ }
+
+ /* Now the main long multiplication loop */
+ /* Unlike the equivalent in the IBM Java implementation, there */
+ /* is no advantage in calculating from msu to lsu. So, do it */
+ /* by the book, as it were. */
+ /* Each iteration calculates ACC=ACC+MULTAND*MULT */
+ accunits=1; /* accumulator starts at '0' */
+ *acc=0; /* .. (lsu=0) */
+ shift=0; /* no multiplicand shift at first */
+ madlength=D2U(lhs->digits); /* this won't change */
+ mermsup=rhs->lsu+D2U(rhs->digits); /* -> msu+1 of multiplier */
+
+ for (mer=rhs->lsu; mer<mermsup; mer++) {
+ /* Here, *mer is the next Unit in the multiplier to use */
+ /* If non-zero [optimization] add it... */
+ if (*mer!=0) accunits=decUnitAddSub(&acc[shift], accunits-shift,
+ lhs->lsu, madlength, 0,
+ &acc[shift], *mer)
+ + shift;
+ else { /* extend acc with a 0; it will be used shortly */
+ *(acc+accunits)=0; /* [this avoids length of <=0 later] */
+ accunits++;
+ }
+ /* multiply multiplicand by 10**DECDPUN for next Unit to left */
+ shift++; /* add this for 'logical length' */
+ } /* n */
+ #if FASTMUL
+ } /* unchunked units */
+ #endif
+ /* common end-path */
+ #if DECTRACE
+ decDumpAr('*', acc, accunits); /* Show exact result */
+ #endif
+
+ /* acc now contains the exact result of the multiplication, */
+ /* possibly with a leading zero unit; build the decNumber from */
+ /* it, noting if any residue */
+ res->bits=bits; /* set sign */
+ res->digits=decGetDigits(acc, accunits); /* count digits exactly */
+
+ /* There can be a 31-bit wrap in calculating the exponent. */
+ /* This can only happen if both input exponents are negative and */
+ /* both their magnitudes are large. If there was a wrap, set a */
+ /* safe very negative exponent, from which decFinalize() will */
+ /* raise a hard underflow shortly. */
+ exponent=lhs->exponent+rhs->exponent; /* calculate exponent */
+ if (lhs->exponent<0 && rhs->exponent<0 && exponent>0)
+ exponent=-2*DECNUMMAXE; /* force underflow */
+ res->exponent=exponent; /* OK to overwrite now */
+
+
+ /* Set the coefficient. If any rounding, residue records */
+ decSetCoeff(res, set, acc, res->digits, &residue, status);
+ decFinish(res, set, &residue, status); /* final cleanup */
+ } while(0); /* end protected */
+
+ if (allocacc!=NULL) free(allocacc); /* drop any storage used */
+ #if DECSUBSET
+ if (allocrhs!=NULL) free(allocrhs); /* .. */
+ if (alloclhs!=NULL) free(alloclhs); /* .. */
+ #endif
+ #if FASTMUL
+ if (allocrhi!=NULL) free(allocrhi); /* .. */
+ if (alloclhi!=NULL) free(alloclhi); /* .. */
+ #endif
+ return res;
+ } /* decMultiplyOp */
+
+/* ------------------------------------------------------------------ */
+/* decExpOp -- effect exponentiation */
+/* */
+/* This computes C = exp(A) */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context; note that rounding mode has no effect */
+/* */
+/* C must have space for set->digits digits. status is updated but */
+/* not set. */
+/* */
+/* Restrictions: */
+/* */
+/* digits, emax, and -emin in the context must be less than */
+/* 2*DEC_MAX_MATH (1999998), and the rhs must be within these */
+/* bounds or a zero. This is an internal routine, so these */
+/* restrictions are contractual and not enforced. */
+/* */
+/* A finite result is rounded using DEC_ROUND_HALF_EVEN; it will */
+/* almost always be correctly rounded, but may be up to 1 ulp in */
+/* error in rare cases. */
+/* */
+/* Finite results will always be full precision and Inexact, except */
+/* when A is a zero or -Infinity (giving 1 or 0 respectively). */
+/* ------------------------------------------------------------------ */
+/* This approach used here is similar to the algorithm described in */
+/* */
+/* Variable Precision Exponential Function, T. E. Hull and */
+/* A. Abrham, ACM Transactions on Mathematical Software, Vol 12 #2, */
+/* pp79-91, ACM, June 1986. */
+/* */
+/* with the main difference being that the iterations in the series */
+/* evaluation are terminated dynamically (which does not require the */
+/* extra variable-precision variables which are expensive in this */
+/* context). */
+/* */
+/* The error analysis in Hull & Abrham's paper applies except for the */
+/* round-off error accumulation during the series evaluation. This */
+/* code does not precalculate the number of iterations and so cannot */
+/* use Horner's scheme. Instead, the accumulation is done at double- */
+/* precision, which ensures that the additions of the terms are exact */
+/* and do not accumulate round-off (and any round-off errors in the */
+/* terms themselves move 'to the right' faster than they can */
+/* accumulate). This code also extends the calculation by allowing, */
+/* in the spirit of other decNumber operators, the input to be more */
+/* precise than the result (the precision used is based on the more */
+/* precise of the input or requested result). */
+/* */
+/* Implementation notes: */
+/* */
+/* 1. This is separated out as decExpOp so it can be called from */
+/* other Mathematical functions (notably Ln) with a wider range */
+/* than normal. In particular, it can handle the slightly wider */
+/* (double) range needed by Ln (which has to be able to calculate */
+/* exp(-x) where x can be the tiniest number (Ntiny). */
+/* */
+/* 2. Normalizing x to be <=0.1 (instead of <=1) reduces loop */
+/* iterations by appoximately a third with additional (although */
+/* diminishing) returns as the range is reduced to even smaller */
+/* fractions. However, h (the power of 10 used to correct the */
+/* result at the end, see below) must be kept <=8 as otherwise */
+/* the final result cannot be computed. Hence the leverage is a */
+/* sliding value (8-h), where potentially the range is reduced */
+/* more for smaller values. */
+/* */
+/* The leverage that can be applied in this way is severely */
+/* limited by the cost of the raise-to-the power at the end, */
+/* which dominates when the number of iterations is small (less */
+/* than ten) or when rhs is short. As an example, the adjustment */
+/* x**10,000,000 needs 31 multiplications, all but one full-width. */
+/* */
+/* 3. The restrictions (especially precision) could be raised with */
+/* care, but the full decNumber range seems very hard within the */
+/* 32-bit limits. */
+/* */
+/* 4. The working precisions for the static buffers are twice the */
+/* obvious size to allow for calls from decNumberPower. */
+/* ------------------------------------------------------------------ */
+decNumber * decExpOp(decNumber *res, const decNumber *rhs,
+ decContext *set, uInt *status) {
+ uInt ignore=0; /* working status */
+ Int h; /* adjusted exponent for 0.xxxx */
+ Int p; /* working precision */
+ Int residue; /* rounding residue */
+ uInt needbytes; /* for space calculations */
+ const decNumber *x=rhs; /* (may point to safe copy later) */
+ decContext aset, tset, dset; /* working contexts */
+ Int comp; /* work */
+
+ /* the argument is often copied to normalize it, so (unusually) it */
+ /* is treated like other buffers, using DECBUFFER, +1 in case */
+ /* DECBUFFER is 0 */
+ decNumber bufr[D2N(DECBUFFER*2+1)];
+ decNumber *allocrhs=NULL; /* non-NULL if rhs buffer allocated */
+
+ /* the working precision will be no more than set->digits+8+1 */
+ /* so for on-stack buffers DECBUFFER+9 is used, +1 in case DECBUFFER */
+ /* is 0 (and twice that for the accumulator) */
+
+ /* buffer for t, term (working precision plus) */
+ decNumber buft[D2N(DECBUFFER*2+9+1)];
+ decNumber *allocbuft=NULL; /* -> allocated buft, iff allocated */
+ decNumber *t=buft; /* term */
+ /* buffer for a, accumulator (working precision * 2), at least 9 */
+ decNumber bufa[D2N(DECBUFFER*4+18+1)];
+ decNumber *allocbufa=NULL; /* -> allocated bufa, iff allocated */
+ decNumber *a=bufa; /* accumulator */
+ /* decNumber for the divisor term; this needs at most 9 digits */
+ /* and so can be fixed size [16 so can use standard context] */
+ decNumber bufd[D2N(16)];
+ decNumber *d=bufd; /* divisor */
+ decNumber numone; /* constant 1 */
+
+ #if DECCHECK
+ Int iterations=0; /* for later sanity check */
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ do { /* protect allocated storage */
+ if (SPECIALARG) { /* handle infinities and NaNs */
+ if (decNumberIsInfinite(rhs)) { /* an infinity */
+ if (decNumberIsNegative(rhs)) /* -Infinity -> +0 */
+ uprv_decNumberZero(res);
+ else uprv_decNumberCopy(res, rhs); /* +Infinity -> self */
+ }
+ else decNaNs(res, rhs, NULL, set, status); /* a NaN */
+ break;}
+
+ if (ISZERO(rhs)) { /* zeros -> exact 1 */
+ uprv_decNumberZero(res); /* make clean 1 */
+ *res->lsu=1; /* .. */
+ break;} /* [no status to set] */
+
+ /* e**x when 0 < x < 0.66 is < 1+3x/2, hence can fast-path */
+ /* positive and negative tiny cases which will result in inexact */
+ /* 1. This also allows the later add-accumulate to always be */
+ /* exact (because its length will never be more than twice the */
+ /* working precision). */
+ /* The comparator (tiny) needs just one digit, so use the */
+ /* decNumber d for it (reused as the divisor, etc., below); its */
+ /* exponent is such that if x is positive it will have */
+ /* set->digits-1 zeros between the decimal point and the digit, */
+ /* which is 4, and if x is negative one more zero there as the */
+ /* more precise result will be of the form 0.9999999 rather than */
+ /* 1.0000001. Hence, tiny will be 0.0000004 if digits=7 and x>0 */
+ /* or 0.00000004 if digits=7 and x<0. If RHS not larger than */
+ /* this then the result will be 1.000000 */
+ uprv_decNumberZero(d); /* clean */
+ *d->lsu=4; /* set 4 .. */
+ d->exponent=-set->digits; /* * 10**(-d) */
+ if (decNumberIsNegative(rhs)) d->exponent--; /* negative case */
+ comp=decCompare(d, rhs, 1); /* signless compare */
+ if (comp==BADINT) {
+ *status|=DEC_Insufficient_storage;
+ break;}
+ if (comp>=0) { /* rhs < d */
+ Int shift=set->digits-1;
+ uprv_decNumberZero(res); /* set 1 */
+ *res->lsu=1; /* .. */
+ res->digits=decShiftToMost(res->lsu, 1, shift);
+ res->exponent=-shift; /* make 1.0000... */
+ *status|=DEC_Inexact | DEC_Rounded; /* .. inexactly */
+ break;} /* tiny */
+
+ /* set up the context to be used for calculating a, as this is */
+ /* used on both paths below */
+ uprv_decContextDefault(&aset, DEC_INIT_DECIMAL64);
+ /* accumulator bounds are as requested (could underflow) */
+ aset.emax=set->emax; /* usual bounds */
+ aset.emin=set->emin; /* .. */
+ aset.clamp=0; /* and no concrete format */
+
+ /* calculate the adjusted (Hull & Abrham) exponent (where the */
+ /* decimal point is just to the left of the coefficient msd) */
+ h=rhs->exponent+rhs->digits;
+ /* if h>8 then 10**h cannot be calculated safely; however, when */
+ /* h=8 then exp(|rhs|) will be at least exp(1E+7) which is at */
+ /* least 6.59E+4342944, so (due to the restriction on Emax/Emin) */
+ /* overflow (or underflow to 0) is guaranteed -- so this case can */
+ /* be handled by simply forcing the appropriate excess */
+ if (h>8) { /* overflow/underflow */
+ /* set up here so Power call below will over or underflow to */
+ /* zero; set accumulator to either 2 or 0.02 */
+ /* [stack buffer for a is always big enough for this] */
+ uprv_decNumberZero(a);
+ *a->lsu=2; /* not 1 but < exp(1) */
+ if (decNumberIsNegative(rhs)) a->exponent=-2; /* make 0.02 */
+ h=8; /* clamp so 10**h computable */
+ p=9; /* set a working precision */
+ }
+ else { /* h<=8 */
+ Int maxlever=(rhs->digits>8?1:0);
+ /* [could/should increase this for precisions >40 or so, too] */
+
+ /* if h is 8, cannot normalize to a lower upper limit because */
+ /* the final result will not be computable (see notes above), */
+ /* but leverage can be applied whenever h is less than 8. */
+ /* Apply as much as possible, up to a MAXLEVER digits, which */
+ /* sets the tradeoff against the cost of the later a**(10**h). */
+ /* As h is increased, the working precision below also */
+ /* increases to compensate for the "constant digits at the */
+ /* front" effect. */
+ Int lever=MINI(8-h, maxlever); /* leverage attainable */
+ Int use=-rhs->digits-lever; /* exponent to use for RHS */
+ h+=lever; /* apply leverage selected */
+ if (h<0) { /* clamp */
+ use+=h; /* [may end up subnormal] */
+ h=0;
+ }
+ /* Take a copy of RHS if it needs normalization (true whenever x>=1) */
+ if (rhs->exponent!=use) {
+ decNumber *newrhs=bufr; /* assume will fit on stack */
+ needbytes=sizeof(decNumber)+(D2U(rhs->digits)-1)*sizeof(Unit);
+ if (needbytes>sizeof(bufr)) { /* need malloc space */
+ allocrhs=(decNumber *)malloc(needbytes);
+ if (allocrhs==NULL) { /* hopeless -- abandon */
+ *status|=DEC_Insufficient_storage;
+ break;}
+ newrhs=allocrhs; /* use the allocated space */
+ }
+ uprv_decNumberCopy(newrhs, rhs); /* copy to safe space */
+ newrhs->exponent=use; /* normalize; now <1 */
+ x=newrhs; /* ready for use */
+ /* decNumberShow(x); */
+ }
+
+ /* Now use the usual power series to evaluate exp(x). The */
+ /* series starts as 1 + x + x^2/2 ... so prime ready for the */
+ /* third term by setting the term variable t=x, the accumulator */
+ /* a=1, and the divisor d=2. */
+
+ /* First determine the working precision. From Hull & Abrham */
+ /* this is set->digits+h+2. However, if x is 'over-precise' we */
+ /* need to allow for all its digits to potentially participate */
+ /* (consider an x where all the excess digits are 9s) so in */
+ /* this case use x->digits+h+2 */
+ p=MAXI(x->digits, set->digits)+h+2; /* [h<=8] */
+
+ /* a and t are variable precision, and depend on p, so space */
+ /* must be allocated for them if necessary */
+
+ /* the accumulator needs to be able to hold 2p digits so that */
+ /* the additions on the second and subsequent iterations are */
+ /* sufficiently exact. */
+ needbytes=sizeof(decNumber)+(D2U(p*2)-1)*sizeof(Unit);
+ if (needbytes>sizeof(bufa)) { /* need malloc space */
+ allocbufa=(decNumber *)malloc(needbytes);
+ if (allocbufa==NULL) { /* hopeless -- abandon */
+ *status|=DEC_Insufficient_storage;
+ break;}
+ a=allocbufa; /* use the allocated space */
+ }
+ /* the term needs to be able to hold p digits (which is */
+ /* guaranteed to be larger than x->digits, so the initial copy */
+ /* is safe); it may also be used for the raise-to-power */
+ /* calculation below, which needs an extra two digits */
+ needbytes=sizeof(decNumber)+(D2U(p+2)-1)*sizeof(Unit);
+ if (needbytes>sizeof(buft)) { /* need malloc space */
+ allocbuft=(decNumber *)malloc(needbytes);
+ if (allocbuft==NULL) { /* hopeless -- abandon */
+ *status|=DEC_Insufficient_storage;
+ break;}
+ t=allocbuft; /* use the allocated space */
+ }
+
+ uprv_decNumberCopy(t, x); /* term=x */
+ uprv_decNumberZero(a); *a->lsu=1; /* accumulator=1 */
+ uprv_decNumberZero(d); *d->lsu=2; /* divisor=2 */
+ uprv_decNumberZero(&numone); *numone.lsu=1; /* constant 1 for increment */
+
+ /* set up the contexts for calculating a, t, and d */
+ uprv_decContextDefault(&tset, DEC_INIT_DECIMAL64);
+ dset=tset;
+ /* accumulator bounds are set above, set precision now */
+ aset.digits=p*2; /* double */
+ /* term bounds avoid any underflow or overflow */
+ tset.digits=p;
+ tset.emin=DEC_MIN_EMIN; /* [emax is plenty] */
+ /* [dset.digits=16, etc., are sufficient] */
+
+ /* finally ready to roll */
+ for (;;) {
+ #if DECCHECK
+ iterations++;
+ #endif
+ /* only the status from the accumulation is interesting */
+ /* [but it should remain unchanged after first add] */
+ decAddOp(a, a, t, &aset, 0, status); /* a=a+t */
+ decMultiplyOp(t, t, x, &tset, &ignore); /* t=t*x */
+ decDivideOp(t, t, d, &tset, DIVIDE, &ignore); /* t=t/d */
+ /* the iteration ends when the term cannot affect the result, */
+ /* if rounded to p digits, which is when its value is smaller */
+ /* than the accumulator by p+1 digits. There must also be */
+ /* full precision in a. */
+ if (((a->digits+a->exponent)>=(t->digits+t->exponent+p+1))
+ && (a->digits>=p)) break;
+ decAddOp(d, d, &numone, &dset, 0, &ignore); /* d=d+1 */
+ } /* iterate */
+
+ #if DECCHECK
+ /* just a sanity check; comment out test to show always */
+ if (iterations>p+3)
+ printf("Exp iterations=%ld, status=%08lx, p=%ld, d=%ld\n",
+ (LI)iterations, (LI)*status, (LI)p, (LI)x->digits);
+ #endif
+ } /* h<=8 */
+
+ /* apply postconditioning: a=a**(10**h) -- this is calculated */
+ /* at a slightly higher precision than Hull & Abrham suggest */
+ if (h>0) {
+ Int seenbit=0; /* set once a 1-bit is seen */
+ Int i; /* counter */
+ Int n=powers[h]; /* always positive */
+ aset.digits=p+2; /* sufficient precision */
+ /* avoid the overhead and many extra digits of decNumberPower */
+ /* as all that is needed is the short 'multipliers' loop; here */
+ /* accumulate the answer into t */
+ uprv_decNumberZero(t); *t->lsu=1; /* acc=1 */
+ for (i=1;;i++){ /* for each bit [top bit ignored] */
+ /* abandon if have had overflow or terminal underflow */
+ if (*status & (DEC_Overflow|DEC_Underflow)) { /* interesting? */
+ if (*status&DEC_Overflow || ISZERO(t)) break;}
+ n=n<<1; /* move next bit to testable position */
+ if (n<0) { /* top bit is set */
+ seenbit=1; /* OK, have a significant bit */
+ decMultiplyOp(t, t, a, &aset, status); /* acc=acc*x */
+ }
+ if (i==31) break; /* that was the last bit */
+ if (!seenbit) continue; /* no need to square 1 */
+ decMultiplyOp(t, t, t, &aset, status); /* acc=acc*acc [square] */
+ } /*i*/ /* 32 bits */
+ /* decNumberShow(t); */
+ a=t; /* and carry on using t instead of a */
+ }
+
+ /* Copy and round the result to res */
+ residue=1; /* indicate dirt to right .. */
+ if (ISZERO(a)) residue=0; /* .. unless underflowed to 0 */
+ aset.digits=set->digits; /* [use default rounding] */
+ decCopyFit(res, a, &aset, &residue, status); /* copy & shorten */
+ decFinish(res, set, &residue, status); /* cleanup/set flags */
+ } while(0); /* end protected */
+
+ if (allocrhs !=NULL) free(allocrhs); /* drop any storage used */
+ if (allocbufa!=NULL) free(allocbufa); /* .. */
+ if (allocbuft!=NULL) free(allocbuft); /* .. */
+ /* [status is handled by caller] */
+ return res;
+ } /* decExpOp */
+
+/* ------------------------------------------------------------------ */
+/* Initial-estimate natural logarithm table */
+/* */
+/* LNnn -- 90-entry 16-bit table for values from .10 through .99. */
+/* The result is a 4-digit encode of the coefficient (c=the */
+/* top 14 bits encoding 0-9999) and a 2-digit encode of the */
+/* exponent (e=the bottom 2 bits encoding 0-3) */
+/* */
+/* The resulting value is given by: */
+/* */
+/* v = -c * 10**(-e-3) */
+/* */
+/* where e and c are extracted from entry k = LNnn[x-10] */
+/* where x is truncated (NB) into the range 10 through 99, */
+/* and then c = k>>2 and e = k&3. */
+/* ------------------------------------------------------------------ */
+static const uShort LNnn[90]={9016, 8652, 8316, 8008, 7724, 7456, 7208,
+ 6972, 6748, 6540, 6340, 6148, 5968, 5792, 5628, 5464, 5312,
+ 5164, 5020, 4884, 4748, 4620, 4496, 4376, 4256, 4144, 4032,
+ 39233, 38181, 37157, 36157, 35181, 34229, 33297, 32389, 31501, 30629,
+ 29777, 28945, 28129, 27329, 26545, 25777, 25021, 24281, 23553, 22837,
+ 22137, 21445, 20769, 20101, 19445, 18801, 18165, 17541, 16925, 16321,
+ 15721, 15133, 14553, 13985, 13421, 12865, 12317, 11777, 11241, 10717,
+ 10197, 9685, 9177, 8677, 8185, 7697, 7213, 6737, 6269, 5801,
+ 5341, 4889, 4437, 39930, 35534, 31186, 26886, 22630, 18418, 14254,
+ 10130, 6046, 20055};
+
+/* ------------------------------------------------------------------ */
+/* decLnOp -- effect natural logarithm */
+/* */
+/* This computes C = ln(A) */
+/* */
+/* res is C, the result. C may be A */
+/* rhs is A */
+/* set is the context; note that rounding mode has no effect */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* Notable cases: */
+/* A<0 -> Invalid */
+/* A=0 -> -Infinity (Exact) */
+/* A=+Infinity -> +Infinity (Exact) */
+/* A=1 exactly -> 0 (Exact) */
+/* */
+/* Restrictions (as for Exp): */
+/* */
+/* digits, emax, and -emin in the context must be less than */
+/* DEC_MAX_MATH+11 (1000010), and the rhs must be within these */
+/* bounds or a zero. This is an internal routine, so these */
+/* restrictions are contractual and not enforced. */
+/* */
+/* A finite result is rounded using DEC_ROUND_HALF_EVEN; it will */
+/* almost always be correctly rounded, but may be up to 1 ulp in */
+/* error in rare cases. */
+/* ------------------------------------------------------------------ */
+/* The result is calculated using Newton's method, with each */
+/* iteration calculating a' = a + x * exp(-a) - 1. See, for example, */
+/* Epperson 1989. */
+/* */
+/* The iteration ends when the adjustment x*exp(-a)-1 is tiny enough. */
+/* This has to be calculated at the sum of the precision of x and the */
+/* working precision. */
+/* */
+/* Implementation notes: */
+/* */
+/* 1. This is separated out as decLnOp so it can be called from */
+/* other Mathematical functions (e.g., Log 10) with a wider range */
+/* than normal. In particular, it can handle the slightly wider */
+/* (+9+2) range needed by a power function. */
+/* */
+/* 2. The speed of this function is about 10x slower than exp, as */
+/* it typically needs 4-6 iterations for short numbers, and the */
+/* extra precision needed adds a squaring effect, twice. */
+/* */
+/* 3. Fastpaths are included for ln(10) and ln(2), up to length 40, */
+/* as these are common requests. ln(10) is used by log10(x). */
+/* */
+/* 4. An iteration might be saved by widening the LNnn table, and */
+/* would certainly save at least one if it were made ten times */
+/* bigger, too (for truncated fractions 0.100 through 0.999). */
+/* However, for most practical evaluations, at least four or five */
+/* iterations will be neede -- so this would only speed up by */
+/* 20-25% and that probably does not justify increasing the table */
+/* size. */
+/* */
+/* 5. The static buffers are larger than might be expected to allow */
+/* for calls from decNumberPower. */
+/* ------------------------------------------------------------------ */
+#if defined(__clang__) || U_GCC_MAJOR_MINOR >= 406
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
+#endif
+decNumber * decLnOp(decNumber *res, const decNumber *rhs,
+ decContext *set, uInt *status) {
+ uInt ignore=0; /* working status accumulator */
+ uInt needbytes; /* for space calculations */
+ Int residue; /* rounding residue */
+ Int r; /* rhs=f*10**r [see below] */
+ Int p; /* working precision */
+ Int pp; /* precision for iteration */
+ Int t; /* work */
+
+ /* buffers for a (accumulator, typically precision+2) and b */
+ /* (adjustment calculator, same size) */
+ decNumber bufa[D2N(DECBUFFER+12)];
+ decNumber *allocbufa=NULL; /* -> allocated bufa, iff allocated */
+ decNumber *a=bufa; /* accumulator/work */
+ decNumber bufb[D2N(DECBUFFER*2+2)];
+ decNumber *allocbufb=NULL; /* -> allocated bufa, iff allocated */
+ decNumber *b=bufb; /* adjustment/work */
+
+ decNumber numone; /* constant 1 */
+ decNumber cmp; /* work */
+ decContext aset, bset; /* working contexts */
+
+ #if DECCHECK
+ Int iterations=0; /* for later sanity check */
+ if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
+ #endif
+
+ do { /* protect allocated storage */
+ if (SPECIALARG) { /* handle infinities and NaNs */
+ if (decNumberIsInfinite(rhs)) { /* an infinity */
+ if (decNumberIsNegative(rhs)) /* -Infinity -> error */
+ *status|=DEC_Invalid_operation;
+ else uprv_decNumberCopy(res, rhs); /* +Infinity -> self */
+ }
+ else decNaNs(res, rhs, NULL, set, status); /* a NaN */
+ break;}
+
+ if (ISZERO(rhs)) { /* +/- zeros -> -Infinity */
+ uprv_decNumberZero(res); /* make clean */
+ res->bits=DECINF|DECNEG; /* set - infinity */
+ break;} /* [no status to set] */
+
+ /* Non-zero negatives are bad... */
+ if (decNumberIsNegative(rhs)) { /* -x -> error */
+ *status|=DEC_Invalid_operation;
+ break;}
+
+ /* Here, rhs is positive, finite, and in range */
+
+ /* lookaside fastpath code for ln(2) and ln(10) at common lengths */
+ if (rhs->exponent==0 && set->digits<=40) {
+ #if DECDPUN==1
+ if (rhs->lsu[0]==0 && rhs->lsu[1]==1 && rhs->digits==2) { /* ln(10) */
+ #else
+ if (rhs->lsu[0]==10 && rhs->digits==2) { /* ln(10) */
+ #endif
+ aset=*set; aset.round=DEC_ROUND_HALF_EVEN;
+ #define LN10 "2.302585092994045684017991454684364207601"
+ uprv_decNumberFromString(res, LN10, &aset);
+ *status|=(DEC_Inexact | DEC_Rounded); /* is inexact */
+ break;}
+ if (rhs->lsu[0]==2 && rhs->digits==1) { /* ln(2) */
+ aset=*set; aset.round=DEC_ROUND_HALF_EVEN;
+ #define LN2 "0.6931471805599453094172321214581765680755"
+ uprv_decNumberFromString(res, LN2, &aset);
+ *status|=(DEC_Inexact | DEC_Rounded);
+ break;}
+ } /* integer and short */
+
+ /* Determine the working precision. This is normally the */
+ /* requested precision + 2, with a minimum of 9. However, if */
+ /* the rhs is 'over-precise' then allow for all its digits to */
+ /* potentially participate (consider an rhs where all the excess */
+ /* digits are 9s) so in this case use rhs->digits+2. */
+ p=MAXI(rhs->digits, MAXI(set->digits, 7))+2;
+
+ /* Allocate space for the accumulator and the high-precision */
+ /* adjustment calculator, if necessary. The accumulator must */
+ /* be able to hold p digits, and the adjustment up to */
+ /* rhs->digits+p digits. They are also made big enough for 16 */
+ /* digits so that they can be used for calculating the initial */
+ /* estimate. */
+ needbytes=sizeof(decNumber)+(D2U(MAXI(p,16))-1)*sizeof(Unit);
+ if (needbytes>sizeof(bufa)) { /* need malloc space */
+ allocbufa=(decNumber *)malloc(needbytes);
+ if (allocbufa==NULL) { /* hopeless -- abandon */
+ *status|=DEC_Insufficient_storage;
+ break;}
+ a=allocbufa; /* use the allocated space */
+ }
+ pp=p+rhs->digits;
+ needbytes=sizeof(decNumber)+(D2U(MAXI(pp,16))-1)*sizeof(Unit);
+ if (needbytes>sizeof(bufb)) { /* need malloc space */
+ allocbufb=(decNumber *)malloc(needbytes);
+ if (allocbufb==NULL) { /* hopeless -- abandon */
+ *status|=DEC_Insufficient_storage;
+ break;}
+ b=allocbufb; /* use the allocated space */
+ }
+
+ /* Prepare an initial estimate in acc. Calculate this by */
+ /* considering the coefficient of x to be a normalized fraction, */
+ /* f, with the decimal point at far left and multiplied by */
+ /* 10**r. Then, rhs=f*10**r and 0.1<=f<1, and */
+ /* ln(x) = ln(f) + ln(10)*r */
+ /* Get the initial estimate for ln(f) from a small lookup */
+ /* table (see above) indexed by the first two digits of f, */
+ /* truncated. */
+
+ uprv_decContextDefault(&aset, DEC_INIT_DECIMAL64); /* 16-digit extended */
+ r=rhs->exponent+rhs->digits; /* 'normalised' exponent */
+ uprv_decNumberFromInt32(a, r); /* a=r */
+ uprv_decNumberFromInt32(b, 2302585); /* b=ln(10) (2.302585) */
+ b->exponent=-6; /* .. */
+ decMultiplyOp(a, a, b, &aset, &ignore); /* a=a*b */
+ /* now get top two digits of rhs into b by simple truncate and */
+ /* force to integer */
+ residue=0; /* (no residue) */
+ aset.digits=2; aset.round=DEC_ROUND_DOWN;
+ decCopyFit(b, rhs, &aset, &residue, &ignore); /* copy & shorten */
+ b->exponent=0; /* make integer */
+ t=decGetInt(b); /* [cannot fail] */
+ if (t<10) t=X10(t); /* adjust single-digit b */
+ t=LNnn[t-10]; /* look up ln(b) */
+ uprv_decNumberFromInt32(b, t>>2); /* b=ln(b) coefficient */
+ b->exponent=-(t&3)-3; /* set exponent */
+ b->bits=DECNEG; /* ln(0.10)->ln(0.99) always -ve */
+ aset.digits=16; aset.round=DEC_ROUND_HALF_EVEN; /* restore */
+ decAddOp(a, a, b, &aset, 0, &ignore); /* acc=a+b */
+ /* the initial estimate is now in a, with up to 4 digits correct. */
+ /* When rhs is at or near Nmax the estimate will be low, so we */
+ /* will approach it from below, avoiding overflow when calling exp. */
+
+ uprv_decNumberZero(&numone); *numone.lsu=1; /* constant 1 for adjustment */
+
+ /* accumulator bounds are as requested (could underflow, but */
+ /* cannot overflow) */
+ aset.emax=set->emax;
+ aset.emin=set->emin;
+ aset.clamp=0; /* no concrete format */
+ /* set up a context to be used for the multiply and subtract */
+ bset=aset;
+ bset.emax=DEC_MAX_MATH*2; /* use double bounds for the */
+ bset.emin=-DEC_MAX_MATH*2; /* adjustment calculation */
+ /* [see decExpOp call below] */
+ /* for each iteration double the number of digits to calculate, */
+ /* up to a maximum of p */
+ pp=9; /* initial precision */
+ /* [initially 9 as then the sequence starts 7+2, 16+2, and */
+ /* 34+2, which is ideal for standard-sized numbers] */
+ aset.digits=pp; /* working context */
+ bset.digits=pp+rhs->digits; /* wider context */
+ for (;;) { /* iterate */
+ #if DECCHECK
+ iterations++;
+ if (iterations>24) break; /* consider 9 * 2**24 */
+ #endif
+ /* calculate the adjustment (exp(-a)*x-1) into b. This is a */
+ /* catastrophic subtraction but it really is the difference */
+ /* from 1 that is of interest. */
+ /* Use the internal entry point to Exp as it allows the double */
+ /* range for calculating exp(-a) when a is the tiniest subnormal. */
+ a->bits^=DECNEG; /* make -a */
+ decExpOp(b, a, &bset, &ignore); /* b=exp(-a) */
+ a->bits^=DECNEG; /* restore sign of a */
+ /* now multiply by rhs and subtract 1, at the wider precision */
+ decMultiplyOp(b, b, rhs, &bset, &ignore); /* b=b*rhs */
+ decAddOp(b, b, &numone, &bset, DECNEG, &ignore); /* b=b-1 */
+
+ /* the iteration ends when the adjustment cannot affect the */
+ /* result by >=0.5 ulp (at the requested digits), which */
+ /* is when its value is smaller than the accumulator by */
+ /* set->digits+1 digits (or it is zero) -- this is a looser */
+ /* requirement than for Exp because all that happens to the */
+ /* accumulator after this is the final rounding (but note that */
+ /* there must also be full precision in a, or a=0). */
+
+ if (decNumberIsZero(b) ||
+ (a->digits+a->exponent)>=(b->digits+b->exponent+set->digits+1)) {
+ if (a->digits==p) break;
+ if (decNumberIsZero(a)) {
+ decCompareOp(&cmp, rhs, &numone, &aset, COMPARE, &ignore); /* rhs=1 ? */
+ if (cmp.lsu[0]==0) a->exponent=0; /* yes, exact 0 */
+ else *status|=(DEC_Inexact | DEC_Rounded); /* no, inexact */
+ break;
+ }
+ /* force padding if adjustment has gone to 0 before full length */
+ if (decNumberIsZero(b)) b->exponent=a->exponent-p;
+ }
+
+ /* not done yet ... */
+ decAddOp(a, a, b, &aset, 0, &ignore); /* a=a+b for next estimate */
+ if (pp==p) continue; /* precision is at maximum */
+ /* lengthen the next calculation */
+ pp=pp*2; /* double precision */
+ if (pp>p) pp=p; /* clamp to maximum */
+ aset.digits=pp; /* working context */
+ bset.digits=pp+rhs->digits; /* wider context */
+ } /* Newton's iteration */
+
+ #if DECCHECK
+ /* just a sanity check; remove the test to show always */
+ if (iterations>24)
+ printf("Ln iterations=%ld, status=%08lx, p=%ld, d=%ld\n",
+ (LI)iterations, (LI)*status, (LI)p, (LI)rhs->digits);
+ #endif
+
+ /* Copy and round the result to res */
+ residue=1; /* indicate dirt to right */
+ if (ISZERO(a)) residue=0; /* .. unless underflowed to 0 */
+ aset.digits=set->digits; /* [use default rounding] */
+ decCopyFit(res, a, &aset, &residue, status); /* copy & shorten */
+ decFinish(res, set, &residue, status); /* cleanup/set flags */
+ } while(0); /* end protected */
+
+ if (allocbufa!=NULL) free(allocbufa); /* drop any storage used */
+ if (allocbufb!=NULL) free(allocbufb); /* .. */
+ /* [status is handled by caller] */
+ return res;
+ } /* decLnOp */
+#if defined(__clang__) || U_GCC_MAJOR_MINOR >= 406
+#pragma GCC diagnostic pop
+#endif
+
+/* ------------------------------------------------------------------ */
+/* decQuantizeOp -- force exponent to requested value */
+/* */
+/* This computes C = op(A, B), where op adjusts the coefficient */
+/* of C (by rounding or shifting) such that the exponent (-scale) */
+/* of C has the value B or matches the exponent of B. */
+/* The numerical value of C will equal A, except for the effects of */
+/* any rounding that occurred. */
+/* */
+/* res is C, the result. C may be A or B */
+/* lhs is A, the number to adjust */
+/* rhs is B, the requested exponent */
+/* set is the context */
+/* quant is 1 for quantize or 0 for rescale */
+/* status is the status accumulator (this can be called without */
+/* risk of control loss) */
+/* */
+/* C must have space for set->digits digits. */
+/* */
+/* Unless there is an error or the result is infinite, the exponent */
+/* after the operation is guaranteed to be that requested. */
+/* ------------------------------------------------------------------ */
+static decNumber * decQuantizeOp(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set,
+ Flag quant, uInt *status) {
+ #if DECSUBSET
+ decNumber *alloclhs=NULL; /* non-NULL if rounded lhs allocated */
+ decNumber *allocrhs=NULL; /* .., rhs */
+ #endif
+ const decNumber *inrhs=rhs; /* save original rhs */
+ Int reqdigits=set->digits; /* requested DIGITS */
+ Int reqexp; /* requested exponent [-scale] */
+ Int residue=0; /* rounding residue */
+ Int etiny=set->emin-(reqdigits-1);
+
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ do { /* protect allocated storage */
+ #if DECSUBSET
+ if (!set->extended) {
+ /* reduce operands and set lostDigits status, as needed */
+ if (lhs->digits>reqdigits) {
+ alloclhs=decRoundOperand(lhs, set, status);
+ if (alloclhs==NULL) break;
+ lhs=alloclhs;
+ }
+ if (rhs->digits>reqdigits) { /* [this only checks lostDigits] */
+ allocrhs=decRoundOperand(rhs, set, status);
+ if (allocrhs==NULL) break;
+ rhs=allocrhs;
+ }
+ }
+ #endif
+ /* [following code does not require input rounding] */
+
+ /* Handle special values */
+ if (SPECIALARGS) {
+ /* NaNs get usual processing */
+ if (SPECIALARGS & (DECSNAN | DECNAN))
+ decNaNs(res, lhs, rhs, set, status);
+ /* one infinity but not both is bad */
+ else if ((lhs->bits ^ rhs->bits) & DECINF)
+ *status|=DEC_Invalid_operation;
+ /* both infinity: return lhs */
+ else uprv_decNumberCopy(res, lhs); /* [nop if in place] */
+ break;
+ }
+
+ /* set requested exponent */
+ if (quant) reqexp=inrhs->exponent; /* quantize -- match exponents */
+ else { /* rescale -- use value of rhs */
+ /* Original rhs must be an integer that fits and is in range, */
+ /* which could be from -1999999997 to +999999999, thanks to */
+ /* subnormals */
+ reqexp=decGetInt(inrhs); /* [cannot fail] */
+ }
+
+ #if DECSUBSET
+ if (!set->extended) etiny=set->emin; /* no subnormals */
+ #endif
+
+ if (reqexp==BADINT /* bad (rescale only) or .. */
+ || reqexp==BIGODD || reqexp==BIGEVEN /* very big (ditto) or .. */
+ || (reqexp<etiny) /* < lowest */
+ || (reqexp>set->emax)) { /* > emax */
+ *status|=DEC_Invalid_operation;
+ break;}
+
+ /* the RHS has been processed, so it can be overwritten now if necessary */
+ if (ISZERO(lhs)) { /* zero coefficient unchanged */
+ uprv_decNumberCopy(res, lhs); /* [nop if in place] */
+ res->exponent=reqexp; /* .. just set exponent */
+ #if DECSUBSET
+ if (!set->extended) res->bits=0; /* subset specification; no -0 */
+ #endif
+ }
+ else { /* non-zero lhs */
+ Int adjust=reqexp-lhs->exponent; /* digit adjustment needed */
+ /* if adjusted coefficient will definitely not fit, give up now */
+ if ((lhs->digits-adjust)>reqdigits) {
+ *status|=DEC_Invalid_operation;
+ break;
+ }
+
+ if (adjust>0) { /* increasing exponent */
+ /* this will decrease the length of the coefficient by adjust */
+ /* digits, and must round as it does so */
+ decContext workset; /* work */
+ workset=*set; /* clone rounding, etc. */
+ workset.digits=lhs->digits-adjust; /* set requested length */
+ /* [note that the latter can be <1, here] */
+ decCopyFit(res, lhs, &workset, &residue, status); /* fit to result */
+ decApplyRound(res, &workset, residue, status); /* .. and round */
+ residue=0; /* [used] */
+ /* If just rounded a 999s case, exponent will be off by one; */
+ /* adjust back (after checking space), if so. */
+ if (res->exponent>reqexp) {
+ /* re-check needed, e.g., for quantize(0.9999, 0.001) under */
+ /* set->digits==3 */
+ if (res->digits==reqdigits) { /* cannot shift by 1 */
+ *status&=~(DEC_Inexact | DEC_Rounded); /* [clean these] */
+ *status|=DEC_Invalid_operation;
+ break;
+ }
+ res->digits=decShiftToMost(res->lsu, res->digits, 1); /* shift */
+ res->exponent--; /* (re)adjust the exponent. */
+ }
+ #if DECSUBSET
+ if (ISZERO(res) && !set->extended) res->bits=0; /* subset; no -0 */
+ #endif
+ } /* increase */
+ else /* adjust<=0 */ { /* decreasing or = exponent */
+ /* this will increase the length of the coefficient by -adjust */
+ /* digits, by adding zero or more trailing zeros; this is */
+ /* already checked for fit, above */
+ uprv_decNumberCopy(res, lhs); /* [it will fit] */
+ /* if padding needed (adjust<0), add it now... */
+ if (adjust<0) {
+ res->digits=decShiftToMost(res->lsu, res->digits, -adjust);
+ res->exponent+=adjust; /* adjust the exponent */
+ }
+ } /* decrease */
+ } /* non-zero */
+
+ /* Check for overflow [do not use Finalize in this case, as an */
+ /* overflow here is a "don't fit" situation] */
+ if (res->exponent>set->emax-res->digits+1) { /* too big */
+ *status|=DEC_Invalid_operation;
+ break;
+ }
+ else {
+ decFinalize(res, set, &residue, status); /* set subnormal flags */
+ *status&=~DEC_Underflow; /* suppress Underflow [as per 754] */
+ }
+ } while(0); /* end protected */
+
+ #if DECSUBSET
+ if (allocrhs!=NULL) free(allocrhs); /* drop any storage used */
+ if (alloclhs!=NULL) free(alloclhs); /* .. */
+ #endif
+ return res;
+ } /* decQuantizeOp */
+
+/* ------------------------------------------------------------------ */
+/* decCompareOp -- compare, min, or max two Numbers */
+/* */
+/* This computes C = A ? B and carries out one of four operations: */
+/* COMPARE -- returns the signum (as a number) giving the */
+/* result of a comparison unless one or both */
+/* operands is a NaN (in which case a NaN results) */
+/* COMPSIG -- as COMPARE except that a quiet NaN raises */
+/* Invalid operation. */
+/* COMPMAX -- returns the larger of the operands, using the */
+/* 754 maxnum operation */
+/* COMPMAXMAG -- ditto, comparing absolute values */
+/* COMPMIN -- the 754 minnum operation */
+/* COMPMINMAG -- ditto, comparing absolute values */
+/* COMTOTAL -- returns the signum (as a number) giving the */
+/* result of a comparison using 754 total ordering */
+/* */
+/* res is C, the result. C may be A and/or B (e.g., X=X?X) */
+/* lhs is A */
+/* rhs is B */
+/* set is the context */
+/* op is the operation flag */
+/* status is the usual accumulator */
+/* */
+/* C must have space for one digit for COMPARE or set->digits for */
+/* COMPMAX, COMPMIN, COMPMAXMAG, or COMPMINMAG. */
+/* ------------------------------------------------------------------ */
+/* The emphasis here is on speed for common cases, and avoiding */
+/* coefficient comparison if possible. */
+/* ------------------------------------------------------------------ */
+static decNumber * decCompareOp(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set,
+ Flag op, uInt *status) {
+ #if DECSUBSET
+ decNumber *alloclhs=NULL; /* non-NULL if rounded lhs allocated */
+ decNumber *allocrhs=NULL; /* .., rhs */
+ #endif
+ Int result=0; /* default result value */
+ uByte merged; /* work */
+
+ #if DECCHECK
+ if (decCheckOperands(res, lhs, rhs, set)) return res;
+ #endif
+
+ do { /* protect allocated storage */
+ #if DECSUBSET
+ if (!set->extended) {
+ /* reduce operands and set lostDigits status, as needed */
+ if (lhs->digits>set->digits) {
+ alloclhs=decRoundOperand(lhs, set, status);
+ if (alloclhs==NULL) {result=BADINT; break;}
+ lhs=alloclhs;
+ }
+ if (rhs->digits>set->digits) {
+ allocrhs=decRoundOperand(rhs, set, status);
+ if (allocrhs==NULL) {result=BADINT; break;}
+ rhs=allocrhs;
+ }
+ }
+ #endif
+ /* [following code does not require input rounding] */
+
+ /* If total ordering then handle differing signs 'up front' */
+ if (op==COMPTOTAL) { /* total ordering */
+ if (decNumberIsNegative(lhs) && !decNumberIsNegative(rhs)) {
+ result=-1;
+ break;
+ }
+ if (!decNumberIsNegative(lhs) && decNumberIsNegative(rhs)) {
+ result=+1;
+ break;
+ }
+ }
+
+ /* handle NaNs specially; let infinities drop through */
+ /* This assumes sNaN (even just one) leads to NaN. */
+ merged=(lhs->bits | rhs->bits) & (DECSNAN | DECNAN);
+ if (merged) { /* a NaN bit set */
+ if (op==COMPARE); /* result will be NaN */
+ else if (op==COMPSIG) /* treat qNaN as sNaN */
+ *status|=DEC_Invalid_operation | DEC_sNaN;
+ else if (op==COMPTOTAL) { /* total ordering, always finite */
+ /* signs are known to be the same; compute the ordering here */
+ /* as if the signs are both positive, then invert for negatives */
+ if (!decNumberIsNaN(lhs)) result=-1;
+ else if (!decNumberIsNaN(rhs)) result=+1;
+ /* here if both NaNs */
+ else if (decNumberIsSNaN(lhs) && decNumberIsQNaN(rhs)) result=-1;
+ else if (decNumberIsQNaN(lhs) && decNumberIsSNaN(rhs)) result=+1;
+ else { /* both NaN or both sNaN */
+ /* now it just depends on the payload */
+ result=decUnitCompare(lhs->lsu, D2U(lhs->digits),
+ rhs->lsu, D2U(rhs->digits), 0);
+ /* [Error not possible, as these are 'aligned'] */
+ } /* both same NaNs */
+ if (decNumberIsNegative(lhs)) result=-result;
+ break;
+ } /* total order */
+
+ else if (merged & DECSNAN); /* sNaN -> qNaN */
+ else { /* here if MIN or MAX and one or two quiet NaNs */
+ /* min or max -- 754 rules ignore single NaN */
+ if (!decNumberIsNaN(lhs) || !decNumberIsNaN(rhs)) {
+ /* just one NaN; force choice to be the non-NaN operand */
+ op=COMPMAX;
+ if (lhs->bits & DECNAN) result=-1; /* pick rhs */
+ else result=+1; /* pick lhs */
+ break;
+ }
+ } /* max or min */
+ op=COMPNAN; /* use special path */
+ decNaNs(res, lhs, rhs, set, status); /* propagate NaN */
+ break;
+ }
+ /* have numbers */
+ if (op==COMPMAXMAG || op==COMPMINMAG) result=decCompare(lhs, rhs, 1);
+ else result=decCompare(lhs, rhs, 0); /* sign matters */
+ } while(0); /* end protected */
+
+ if (result==BADINT) *status|=DEC_Insufficient_storage; /* rare */
+ else {
+ if (op==COMPARE || op==COMPSIG ||op==COMPTOTAL) { /* returning signum */
+ if (op==COMPTOTAL && result==0) {
+ /* operands are numerically equal or same NaN (and same sign, */
+ /* tested first); if identical, leave result 0 */
+ if (lhs->exponent!=rhs->exponent) {
+ if (lhs->exponent<rhs->exponent) result=-1;
+ else result=+1;
+ if (decNumberIsNegative(lhs)) result=-result;
+ } /* lexp!=rexp */
+ } /* total-order by exponent */
+ uprv_decNumberZero(res); /* [always a valid result] */
+ if (result!=0) { /* must be -1 or +1 */
+ *res->lsu=1;
+ if (result<0) res->bits=DECNEG;
+ }
+ }
+ else if (op==COMPNAN); /* special, drop through */
+ else { /* MAX or MIN, non-NaN result */
+ Int residue=0; /* rounding accumulator */
+ /* choose the operand for the result */
+ const decNumber *choice;
+ if (result==0) { /* operands are numerically equal */
+ /* choose according to sign then exponent (see 754) */
+ uByte slhs=(lhs->bits & DECNEG);
+ uByte srhs=(rhs->bits & DECNEG);
+ #if DECSUBSET
+ if (!set->extended) { /* subset: force left-hand */
+ op=COMPMAX;
+ result=+1;
+ }
+ else
+ #endif
+ if (slhs!=srhs) { /* signs differ */
+ if (slhs) result=-1; /* rhs is max */
+ else result=+1; /* lhs is max */
+ }
+ else if (slhs && srhs) { /* both negative */
+ if (lhs->exponent<rhs->exponent) result=+1;
+ else result=-1;
+ /* [if equal, use lhs, technically identical] */
+ }
+ else { /* both positive */
+ if (lhs->exponent>rhs->exponent) result=+1;
+ else result=-1;
+ /* [ditto] */
+ }
+ } /* numerically equal */
+ /* here result will be non-0; reverse if looking for MIN */
+ if (op==COMPMIN || op==COMPMINMAG) result=-result;
+ choice=(result>0 ? lhs : rhs); /* choose */
+ /* copy chosen to result, rounding if need be */
+ decCopyFit(res, choice, set, &residue, status);
+ decFinish(res, set, &residue, status);
+ }
+ }
+ #if DECSUBSET
+ if (allocrhs!=NULL) free(allocrhs); /* free any storage used */
+ if (alloclhs!=NULL) free(alloclhs); /* .. */
+ #endif
+ return res;
+ } /* decCompareOp */
+
+/* ------------------------------------------------------------------ */
+/* decCompare -- compare two decNumbers by numerical value */
+/* */
+/* This routine compares A ? B without altering them. */
+/* */
+/* Arg1 is A, a decNumber which is not a NaN */
+/* Arg2 is B, a decNumber which is not a NaN */
+/* Arg3 is 1 for a sign-independent compare, 0 otherwise */
+/* */
+/* returns -1, 0, or 1 for A<B, A==B, or A>B, or BADINT if failure */
+/* (the only possible failure is an allocation error) */
+/* ------------------------------------------------------------------ */
+static Int decCompare(const decNumber *lhs, const decNumber *rhs,
+ Flag abs_c) {
+ Int result; /* result value */
+ Int sigr; /* rhs signum */
+ Int compare; /* work */
+
+ result=1; /* assume signum(lhs) */
+ if (ISZERO(lhs)) result=0;
+ if (abs_c) {
+ if (ISZERO(rhs)) return result; /* LHS wins or both 0 */
+ /* RHS is non-zero */
+ if (result==0) return -1; /* LHS is 0; RHS wins */
+ /* [here, both non-zero, result=1] */
+ }
+ else { /* signs matter */
+ if (result && decNumberIsNegative(lhs)) result=-1;
+ sigr=1; /* compute signum(rhs) */
+ if (ISZERO(rhs)) sigr=0;
+ else if (decNumberIsNegative(rhs)) sigr=-1;
+ if (result > sigr) return +1; /* L > R, return 1 */
+ if (result < sigr) return -1; /* L < R, return -1 */
+ if (result==0) return 0; /* both 0 */
+ }
+
+ /* signums are the same; both are non-zero */
+ if ((lhs->bits | rhs->bits) & DECINF) { /* one or more infinities */
+ if (decNumberIsInfinite(rhs)) {
+ if (decNumberIsInfinite(lhs)) result=0;/* both infinite */
+ else result=-result; /* only rhs infinite */
+ }
+ return result;
+ }
+ /* must compare the coefficients, allowing for exponents */
+ if (lhs->exponent>rhs->exponent) { /* LHS exponent larger */
+ /* swap sides, and sign */
+ const decNumber *temp=lhs;
+ lhs=rhs;
+ rhs=temp;
+ result=-result;
+ }
+ compare=decUnitCompare(lhs->lsu, D2U(lhs->digits),
+ rhs->lsu, D2U(rhs->digits),
+ rhs->exponent-lhs->exponent);
+ if (compare!=BADINT) compare*=result; /* comparison succeeded */
+ return compare;
+ } /* decCompare */
+
+/* ------------------------------------------------------------------ */
+/* decUnitCompare -- compare two >=0 integers in Unit arrays */
+/* */
+/* This routine compares A ? B*10**E where A and B are unit arrays */
+/* A is a plain integer */
+/* B has an exponent of E (which must be non-negative) */
+/* */
+/* Arg1 is A first Unit (lsu) */
+/* Arg2 is A length in Units */
+/* Arg3 is B first Unit (lsu) */
+/* Arg4 is B length in Units */
+/* Arg5 is E (0 if the units are aligned) */
+/* */
+/* returns -1, 0, or 1 for A<B, A==B, or A>B, or BADINT if failure */
+/* (the only possible failure is an allocation error, which can */
+/* only occur if E!=0) */
+/* ------------------------------------------------------------------ */
+static Int decUnitCompare(const Unit *a, Int alength,
+ const Unit *b, Int blength, Int exp) {
+ Unit *acc; /* accumulator for result */
+ Unit accbuff[SD2U(DECBUFFER*2+1)]; /* local buffer */
+ Unit *allocacc=NULL; /* -> allocated acc buffer, iff allocated */
+ Int accunits, need; /* units in use or needed for acc */
+ const Unit *l, *r, *u; /* work */
+ Int expunits, exprem, result; /* .. */
+
+ if (exp==0) { /* aligned; fastpath */
+ if (alength>blength) return 1;
+ if (alength<blength) return -1;
+ /* same number of units in both -- need unit-by-unit compare */
+ l=a+alength-1;
+ r=b+alength-1;
+ for (;l>=a; l--, r--) {
+ if (*l>*r) return 1;
+ if (*l<*r) return -1;
+ }
+ return 0; /* all units match */
+ } /* aligned */
+
+ /* Unaligned. If one is >1 unit longer than the other, padded */
+ /* approximately, then can return easily */
+ if (alength>blength+(Int)D2U(exp)) return 1;
+ if (alength+1<blength+(Int)D2U(exp)) return -1;
+
+ /* Need to do a real subtract. For this, a result buffer is needed */
+ /* even though only the sign is of interest. Its length needs */
+ /* to be the larger of alength and padded blength, +2 */
+ need=blength+D2U(exp); /* maximum real length of B */
+ if (need<alength) need=alength;
+ need+=2;
+ acc=accbuff; /* assume use local buffer */
+ if (need*sizeof(Unit)>sizeof(accbuff)) {
+ allocacc=(Unit *)malloc(need*sizeof(Unit));
+ if (allocacc==NULL) return BADINT; /* hopeless -- abandon */
+ acc=allocacc;
+ }
+ /* Calculate units and remainder from exponent. */
+ expunits=exp/DECDPUN;
+ exprem=exp%DECDPUN;
+ /* subtract [A+B*(-m)] */
+ accunits=decUnitAddSub(a, alength, b, blength, expunits, acc,
+ -(Int)powers[exprem]);
+ /* [UnitAddSub result may have leading zeros, even on zero] */
+ if (accunits<0) result=-1; /* negative result */
+ else { /* non-negative result */
+ /* check units of the result before freeing any storage */
+ for (u=acc; u<acc+accunits-1 && *u==0;) u++;
+ result=(*u==0 ? 0 : +1);
+ }
+ /* clean up and return the result */
+ if (allocacc!=NULL) free(allocacc); /* drop any storage used */
+ return result;
+ } /* decUnitCompare */
+
+/* ------------------------------------------------------------------ */
+/* decUnitAddSub -- add or subtract two >=0 integers in Unit arrays */
+/* */
+/* This routine performs the calculation: */
+/* */
+/* C=A+(B*M) */
+/* */
+/* Where M is in the range -DECDPUNMAX through +DECDPUNMAX. */
+/* */
+/* A may be shorter or longer than B. */
+/* */
+/* Leading zeros are not removed after a calculation. The result is */
+/* either the same length as the longer of A and B (adding any */
+/* shift), or one Unit longer than that (if a Unit carry occurred). */
+/* */
+/* A and B content are not altered unless C is also A or B. */
+/* C may be the same array as A or B, but only if no zero padding is */
+/* requested (that is, C may be B only if bshift==0). */
+/* C is filled from the lsu; only those units necessary to complete */
+/* the calculation are referenced. */
+/* */
+/* Arg1 is A first Unit (lsu) */
+/* Arg2 is A length in Units */
+/* Arg3 is B first Unit (lsu) */
+/* Arg4 is B length in Units */
+/* Arg5 is B shift in Units (>=0; pads with 0 units if positive) */
+/* Arg6 is C first Unit (lsu) */
+/* Arg7 is M, the multiplier */
+/* */
+/* returns the count of Units written to C, which will be non-zero */
+/* and negated if the result is negative. That is, the sign of the */
+/* returned Int is the sign of the result (positive for zero) and */
+/* the absolute value of the Int is the count of Units. */
+/* */
+/* It is the caller's responsibility to make sure that C size is */
+/* safe, allowing space if necessary for a one-Unit carry. */
+/* */
+/* This routine is severely performance-critical; *any* change here */
+/* must be measured (timed) to assure no performance degradation. */
+/* In particular, trickery here tends to be counter-productive, as */
+/* increased complexity of code hurts register optimizations on */
+/* register-poor architectures. Avoiding divisions is nearly */
+/* always a Good Idea, however. */
+/* */
+/* Special thanks to Rick McGuire (IBM Cambridge, MA) and Dave Clark */
+/* (IBM Warwick, UK) for some of the ideas used in this routine. */
+/* ------------------------------------------------------------------ */
+static Int decUnitAddSub(const Unit *a, Int alength,
+ const Unit *b, Int blength, Int bshift,
+ Unit *c, Int m) {
+ const Unit *alsu=a; /* A lsu [need to remember it] */
+ Unit *clsu=c; /* C ditto */
+ Unit *minC; /* low water mark for C */
+ Unit *maxC; /* high water mark for C */
+ eInt carry=0; /* carry integer (could be Long) */
+ Int add; /* work */
+ #if DECDPUN<=4 /* myriadal, millenary, etc. */
+ Int est; /* estimated quotient */
+ #endif
+
+ #if DECTRACE
+ if (alength<1 || blength<1)
+ printf("decUnitAddSub: alen blen m %ld %ld [%ld]\n", alength, blength, m);
+ #endif
+
+ maxC=c+alength; /* A is usually the longer */
+ minC=c+blength; /* .. and B the shorter */
+ if (bshift!=0) { /* B is shifted; low As copy across */
+ minC+=bshift;
+ /* if in place [common], skip copy unless there's a gap [rare] */
+ if (a==c && bshift<=alength) {
+ c+=bshift;
+ a+=bshift;
+ }
+ else for (; c<clsu+bshift; a++, c++) { /* copy needed */
+ if (a<alsu+alength) *c=*a;
+ else *c=0;
+ }
+ }
+ if (minC>maxC) { /* swap */
+ Unit *hold=minC;
+ minC=maxC;
+ maxC=hold;
+ }
+
+ /* For speed, do the addition as two loops; the first where both A */
+ /* and B contribute, and the second (if necessary) where only one or */
+ /* other of the numbers contribute. */
+ /* Carry handling is the same (i.e., duplicated) in each case. */
+ for (; c<minC; c++) {
+ carry+=*a;
+ a++;
+ carry+=((eInt)*b)*m; /* [special-casing m=1/-1 */
+ b++; /* here is not a win] */
+ /* here carry is new Unit of digits; it could be +ve or -ve */
+ if ((ueInt)carry<=DECDPUNMAX) { /* fastpath 0-DECDPUNMAX */
+ *c=(Unit)carry;
+ carry=0;
+ continue;
+ }
+ #if DECDPUN==4 /* use divide-by-multiply */
+ if (carry>=0) {
+ est=(((ueInt)carry>>11)*53687)>>18;
+ *c=(Unit)(carry-est*(DECDPUNMAX+1)); /* remainder */
+ carry=est; /* likely quotient [89%] */
+ if (*c<DECDPUNMAX+1) continue; /* estimate was correct */
+ carry++;
+ *c-=DECDPUNMAX+1;
+ continue;
+ }
+ /* negative case */
+ carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
+ est=(((ueInt)carry>>11)*53687)>>18;
+ *c=(Unit)(carry-est*(DECDPUNMAX+1));
+ carry=est-(DECDPUNMAX+1); /* correctly negative */
+ if (*c<DECDPUNMAX+1) continue; /* was OK */
+ carry++;
+ *c-=DECDPUNMAX+1;
+ #elif DECDPUN==3
+ if (carry>=0) {
+ est=(((ueInt)carry>>3)*16777)>>21;
+ *c=(Unit)(carry-est*(DECDPUNMAX+1)); /* remainder */
+ carry=est; /* likely quotient [99%] */
+ if (*c<DECDPUNMAX+1) continue; /* estimate was correct */
+ carry++;
+ *c-=DECDPUNMAX+1;
+ continue;
+ }
+ /* negative case */
+ carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
+ est=(((ueInt)carry>>3)*16777)>>21;
+ *c=(Unit)(carry-est*(DECDPUNMAX+1));
+ carry=est-(DECDPUNMAX+1); /* correctly negative */
+ if (*c<DECDPUNMAX+1) continue; /* was OK */
+ carry++;
+ *c-=DECDPUNMAX+1;
+ #elif DECDPUN<=2
+ /* Can use QUOT10 as carry <= 4 digits */
+ if (carry>=0) {
+ est=QUOT10(carry, DECDPUN);
+ *c=(Unit)(carry-est*(DECDPUNMAX+1)); /* remainder */
+ carry=est; /* quotient */
+ continue;
+ }
+ /* negative case */
+ carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
+ est=QUOT10(carry, DECDPUN);
+ *c=(Unit)(carry-est*(DECDPUNMAX+1));
+ carry=est-(DECDPUNMAX+1); /* correctly negative */
+ #else
+ /* remainder operator is undefined if negative, so must test */
+ if ((ueInt)carry<(DECDPUNMAX+1)*2) { /* fastpath carry +1 */
+ *c=(Unit)(carry-(DECDPUNMAX+1)); /* [helps additions] */
+ carry=1;
+ continue;
+ }
+ if (carry>=0) {
+ *c=(Unit)(carry%(DECDPUNMAX+1));
+ carry=carry/(DECDPUNMAX+1);
+ continue;
+ }
+ /* negative case */
+ carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
+ *c=(Unit)(carry%(DECDPUNMAX+1));
+ carry=carry/(DECDPUNMAX+1)-(DECDPUNMAX+1);
+ #endif
+ } /* c */
+
+ /* now may have one or other to complete */
+ /* [pretest to avoid loop setup/shutdown] */
+ if (c<maxC) for (; c<maxC; c++) {
+ if (a<alsu+alength) { /* still in A */
+ carry+=*a;
+ a++;
+ }
+ else { /* inside B */
+ carry+=((eInt)*b)*m;
+ b++;
+ }
+ /* here carry is new Unit of digits; it could be +ve or -ve and */
+ /* magnitude up to DECDPUNMAX squared */
+ if ((ueInt)carry<=DECDPUNMAX) { /* fastpath 0-DECDPUNMAX */
+ *c=(Unit)carry;
+ carry=0;
+ continue;
+ }
+ /* result for this unit is negative or >DECDPUNMAX */
+ #if DECDPUN==4 /* use divide-by-multiply */
+ if (carry>=0) {
+ est=(((ueInt)carry>>11)*53687)>>18;
+ *c=(Unit)(carry-est*(DECDPUNMAX+1)); /* remainder */
+ carry=est; /* likely quotient [79.7%] */
+ if (*c<DECDPUNMAX+1) continue; /* estimate was correct */
+ carry++;
+ *c-=DECDPUNMAX+1;
+ continue;
+ }
+ /* negative case */
+ carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
+ est=(((ueInt)carry>>11)*53687)>>18;
+ *c=(Unit)(carry-est*(DECDPUNMAX+1));
+ carry=est-(DECDPUNMAX+1); /* correctly negative */
+ if (*c<DECDPUNMAX+1) continue; /* was OK */
+ carry++;
+ *c-=DECDPUNMAX+1;
+ #elif DECDPUN==3
+ if (carry>=0) {
+ est=(((ueInt)carry>>3)*16777)>>21;
+ *c=(Unit)(carry-est*(DECDPUNMAX+1)); /* remainder */
+ carry=est; /* likely quotient [99%] */
+ if (*c<DECDPUNMAX+1) continue; /* estimate was correct */
+ carry++;
+ *c-=DECDPUNMAX+1;
+ continue;
+ }
+ /* negative case */
+ carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
+ est=(((ueInt)carry>>3)*16777)>>21;
+ *c=(Unit)(carry-est*(DECDPUNMAX+1));
+ carry=est-(DECDPUNMAX+1); /* correctly negative */
+ if (*c<DECDPUNMAX+1) continue; /* was OK */
+ carry++;
+ *c-=DECDPUNMAX+1;
+ #elif DECDPUN<=2
+ if (carry>=0) {
+ est=QUOT10(carry, DECDPUN);
+ *c=(Unit)(carry-est*(DECDPUNMAX+1)); /* remainder */
+ carry=est; /* quotient */
+ continue;
+ }
+ /* negative case */
+ carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
+ est=QUOT10(carry, DECDPUN);
+ *c=(Unit)(carry-est*(DECDPUNMAX+1));
+ carry=est-(DECDPUNMAX+1); /* correctly negative */
+ #else
+ if ((ueInt)carry<(DECDPUNMAX+1)*2){ /* fastpath carry 1 */
+ *c=(Unit)(carry-(DECDPUNMAX+1));
+ carry=1;
+ continue;
+ }
+ /* remainder operator is undefined if negative, so must test */
+ if (carry>=0) {
+ *c=(Unit)(carry%(DECDPUNMAX+1));
+ carry=carry/(DECDPUNMAX+1);
+ continue;
+ }
+ /* negative case */
+ carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
+ *c=(Unit)(carry%(DECDPUNMAX+1));
+ carry=carry/(DECDPUNMAX+1)-(DECDPUNMAX+1);
+ #endif
+ } /* c */
+
+ /* OK, all A and B processed; might still have carry or borrow */
+ /* return number of Units in the result, negated if a borrow */
+ if (carry==0) return static_cast<int32_t>(c-clsu); /* no carry, so no more to do */
+ if (carry>0) { /* positive carry */
+ *c=(Unit)carry; /* place as new unit */
+ c++; /* .. */
+ return static_cast<int32_t>(c-clsu);
+ }
+ /* -ve carry: it's a borrow; complement needed */
+ add=1; /* temporary carry... */
+ for (c=clsu; c<maxC; c++) {
+ add=DECDPUNMAX+add-*c;
+ if (add<=DECDPUNMAX) {
+ *c=(Unit)add;
+ add=0;
+ }
+ else {
+ *c=0;
+ add=1;
+ }
+ }
+ /* add an extra unit iff it would be non-zero */
+ #if DECTRACE
+ printf("UAS borrow: add %ld, carry %ld\n", add, carry);
+ #endif
+ if ((add-carry-1)!=0) {
+ *c=(Unit)(add-carry-1);
+ c++; /* interesting, include it */
+ }
+ return static_cast<int32_t>(clsu-c); /* -ve result indicates borrowed */
+ } /* decUnitAddSub */
+
+/* ------------------------------------------------------------------ */
+/* decTrim -- trim trailing zeros or normalize */
+/* */
+/* dn is the number to trim or normalize */
+/* set is the context to use to check for clamp */
+/* all is 1 to remove all trailing zeros, 0 for just fraction ones */
+/* noclamp is 1 to unconditional (unclamped) trim */
+/* dropped returns the number of discarded trailing zeros */
+/* returns dn */
+/* */
+/* If clamp is set in the context then the number of zeros trimmed */
+/* may be limited if the exponent is high. */
+/* All fields are updated as required. This is a utility operation, */
+/* so special values are unchanged and no error is possible. */
+/* ------------------------------------------------------------------ */
+static decNumber * decTrim(decNumber *dn, decContext *set, Flag all,
+ Flag noclamp, Int *dropped) {
+ Int d, exp; /* work */
+ uInt cut; /* .. */
+ Unit *up; /* -> current Unit */
+
+ #if DECCHECK
+ if (decCheckOperands(dn, DECUNUSED, DECUNUSED, DECUNCONT)) return dn;
+ #endif
+
+ *dropped=0; /* assume no zeros dropped */
+ if ((dn->bits & DECSPECIAL) /* fast exit if special .. */
+ || (*dn->lsu & 0x01)) return dn; /* .. or odd */
+ if (ISZERO(dn)) { /* .. or 0 */
+ dn->exponent=0; /* (sign is preserved) */
+ return dn;
+ }
+
+ /* have a finite number which is even */
+ exp=dn->exponent;
+ cut=1; /* digit (1-DECDPUN) in Unit */
+ up=dn->lsu; /* -> current Unit */
+ for (d=0; d<dn->digits-1; d++) { /* [don't strip the final digit] */
+ /* slice by powers */
+ #if DECDPUN<=4
+ uInt quot=QUOT10(*up, cut);
+ if ((*up-quot*powers[cut])!=0) break; /* found non-0 digit */
+ #else
+ if (*up%powers[cut]!=0) break; /* found non-0 digit */
+ #endif
+ /* have a trailing 0 */
+ if (!all) { /* trimming */
+ /* [if exp>0 then all trailing 0s are significant for trim] */
+ if (exp<=0) { /* if digit might be significant */
+ if (exp==0) break; /* then quit */
+ exp++; /* next digit might be significant */
+ }
+ }
+ cut++; /* next power */
+ if (cut>DECDPUN) { /* need new Unit */
+ up++;
+ cut=1;
+ }
+ } /* d */
+ if (d==0) return dn; /* none to drop */
+
+ /* may need to limit drop if clamping */
+ if (set->clamp && !noclamp) {
+ Int maxd=set->emax-set->digits+1-dn->exponent;
+ if (maxd<=0) return dn; /* nothing possible */
+ if (d>maxd) d=maxd;
+ }
+
+ /* effect the drop */
+ decShiftToLeast(dn->lsu, D2U(dn->digits), d);
+ dn->exponent+=d; /* maintain numerical value */
+ dn->digits-=d; /* new length */
+ *dropped=d; /* report the count */
+ return dn;
+ } /* decTrim */
+
+/* ------------------------------------------------------------------ */
+/* decReverse -- reverse a Unit array in place */
+/* */
+/* ulo is the start of the array */
+/* uhi is the end of the array (highest Unit to include) */
+/* */
+/* The units ulo through uhi are reversed in place (if the number */
+/* of units is odd, the middle one is untouched). Note that the */
+/* digit(s) in each unit are unaffected. */
+/* ------------------------------------------------------------------ */
+static void decReverse(Unit *ulo, Unit *uhi) {
+ Unit temp;
+ for (; ulo<uhi; ulo++, uhi--) {
+ temp=*ulo;
+ *ulo=*uhi;
+ *uhi=temp;
+ }
+ return;
+ } /* decReverse */
+
+/* ------------------------------------------------------------------ */
+/* decShiftToMost -- shift digits in array towards most significant */
+/* */
+/* uar is the array */
+/* digits is the count of digits in use in the array */
+/* shift is the number of zeros to pad with (least significant); */
+/* it must be zero or positive */
+/* */
+/* returns the new length of the integer in the array, in digits */
+/* */
+/* No overflow is permitted (that is, the uar array must be known to */
+/* be large enough to hold the result, after shifting). */
+/* ------------------------------------------------------------------ */
+static Int decShiftToMost(Unit *uar, Int digits, Int shift) {
+ Unit *target, *source, *first; /* work */
+ Int cut; /* odd 0's to add */
+ uInt next; /* work */
+
+ if (shift==0) return digits; /* [fastpath] nothing to do */
+ if ((digits+shift)<=DECDPUN) { /* [fastpath] single-unit case */
+ *uar=(Unit)(*uar*powers[shift]);
+ return digits+shift;
+ }
+
+ next=0; /* all paths */
+ source=uar+D2U(digits)-1; /* where msu comes from */
+ target=source+D2U(shift); /* where upper part of first cut goes */
+ cut=DECDPUN-MSUDIGITS(shift); /* where to slice */
+ if (cut==0) { /* unit-boundary case */
+ for (; source>=uar; source--, target--) *target=*source;
+ }
+ else {
+ first=uar+D2U(digits+shift)-1; /* where msu of source will end up */
+ for (; source>=uar; source--, target--) {
+ /* split the source Unit and accumulate remainder for next */
+ #if DECDPUN<=4
+ uInt quot=QUOT10(*source, cut);
+ uInt rem=*source-quot*powers[cut];
+ next+=quot;
+ #else
+ uInt rem=*source%powers[cut];
+ next+=*source/powers[cut];
+ #endif
+ if (target<=first) *target=(Unit)next; /* write to target iff valid */
+ next=rem*powers[DECDPUN-cut]; /* save remainder for next Unit */
+ }
+ } /* shift-move */
+
+ /* propagate any partial unit to one below and clear the rest */
+ for (; target>=uar; target--) {
+ *target=(Unit)next;
+ next=0;
+ }
+ return digits+shift;
+ } /* decShiftToMost */
+
+/* ------------------------------------------------------------------ */
+/* decShiftToLeast -- shift digits in array towards least significant */
+/* */
+/* uar is the array */
+/* units is length of the array, in units */
+/* shift is the number of digits to remove from the lsu end; it */
+/* must be zero or positive and <= than units*DECDPUN. */
+/* */
+/* returns the new length of the integer in the array, in units */
+/* */
+/* Removed digits are discarded (lost). Units not required to hold */
+/* the final result are unchanged. */
+/* ------------------------------------------------------------------ */
+static Int decShiftToLeast(Unit *uar, Int units, Int shift) {
+ Unit *target, *up; /* work */
+ Int cut, count; /* work */
+ Int quot, rem; /* for division */
+
+ if (shift==0) return units; /* [fastpath] nothing to do */
+ if (shift==units*DECDPUN) { /* [fastpath] little to do */
+ *uar=0; /* all digits cleared gives zero */
+ return 1; /* leaves just the one */
+ }
+
+ target=uar; /* both paths */
+ cut=MSUDIGITS(shift);
+ if (cut==DECDPUN) { /* unit-boundary case; easy */
+ up=uar+D2U(shift);
+ for (; up<uar+units; target++, up++) *target=*up;
+ return static_cast<int32_t>(target-uar);
+ }
+
+ /* messier */
+ up=uar+D2U(shift-cut); /* source; correct to whole Units */
+ count=units*DECDPUN-shift; /* the maximum new length */
+ #if DECDPUN<=4
+ quot=QUOT10(*up, cut);
+ #else
+ quot=*up/powers[cut];
+ #endif
+ for (; ; target++) {
+ *target=(Unit)quot;
+ count-=(DECDPUN-cut);
+ if (count<=0) break;
+ up++;
+ quot=*up;
+ #if DECDPUN<=4
+ quot=QUOT10(quot, cut);
+ rem=*up-quot*powers[cut];
+ #else
+ rem=quot%powers[cut];
+ quot=quot/powers[cut];
+ #endif
+ *target=(Unit)(*target+rem*powers[DECDPUN-cut]);
+ count-=cut;
+ if (count<=0) break;
+ }
+ return static_cast<int32_t>(target-uar+1);
+ } /* decShiftToLeast */
+
+#if DECSUBSET
+/* ------------------------------------------------------------------ */
+/* decRoundOperand -- round an operand [used for subset only] */
+/* */
+/* dn is the number to round (dn->digits is > set->digits) */
+/* set is the relevant context */
+/* status is the status accumulator */
+/* */
+/* returns an allocated decNumber with the rounded result. */
+/* */
+/* lostDigits and other status may be set by this. */
+/* */
+/* Since the input is an operand, it must not be modified. */
+/* Instead, return an allocated decNumber, rounded as required. */
+/* It is the caller's responsibility to free the allocated storage. */
+/* */
+/* If no storage is available then the result cannot be used, so NULL */
+/* is returned. */
+/* ------------------------------------------------------------------ */
+static decNumber *decRoundOperand(const decNumber *dn, decContext *set,
+ uInt *status) {
+ decNumber *res; /* result structure */
+ uInt newstatus=0; /* status from round */
+ Int residue=0; /* rounding accumulator */
+
+ /* Allocate storage for the returned decNumber, big enough for the */
+ /* length specified by the context */
+ res=(decNumber *)malloc(sizeof(decNumber)
+ +(D2U(set->digits)-1)*sizeof(Unit));
+ if (res==NULL) {
+ *status|=DEC_Insufficient_storage;
+ return NULL;
+ }
+ decCopyFit(res, dn, set, &residue, &newstatus);
+ decApplyRound(res, set, residue, &newstatus);
+
+ /* If that set Inexact then "lost digits" is raised... */
+ if (newstatus & DEC_Inexact) newstatus|=DEC_Lost_digits;
+ *status|=newstatus;
+ return res;
+ } /* decRoundOperand */
+#endif
+
+/* ------------------------------------------------------------------ */
+/* decCopyFit -- copy a number, truncating the coefficient if needed */
+/* */
+/* dest is the target decNumber */
+/* src is the source decNumber */
+/* set is the context [used for length (digits) and rounding mode] */
+/* residue is the residue accumulator */
+/* status contains the current status to be updated */
+/* */
+/* (dest==src is allowed and will be a no-op if fits) */
+/* All fields are updated as required. */
+/* ------------------------------------------------------------------ */
+static void decCopyFit(decNumber *dest, const decNumber *src,
+ decContext *set, Int *residue, uInt *status) {
+ dest->bits=src->bits;
+ dest->exponent=src->exponent;
+ decSetCoeff(dest, set, src->lsu, src->digits, residue, status);
+ } /* decCopyFit */
+
+/* ------------------------------------------------------------------ */
+/* decSetCoeff -- set the coefficient of a number */
+/* */
+/* dn is the number whose coefficient array is to be set. */
+/* It must have space for set->digits digits */
+/* set is the context [for size] */
+/* lsu -> lsu of the source coefficient [may be dn->lsu] */
+/* len is digits in the source coefficient [may be dn->digits] */
+/* residue is the residue accumulator. This has values as in */
+/* decApplyRound, and will be unchanged unless the */
+/* target size is less than len. In this case, the */
+/* coefficient is truncated and the residue is updated to */
+/* reflect the previous residue and the dropped digits. */
+/* status is the status accumulator, as usual */
+/* */
+/* The coefficient may already be in the number, or it can be an */
+/* external intermediate array. If it is in the number, lsu must == */
+/* dn->lsu and len must == dn->digits. */
+/* */
+/* Note that the coefficient length (len) may be < set->digits, and */
+/* in this case this merely copies the coefficient (or is a no-op */
+/* if dn->lsu==lsu). */
+/* */
+/* Note also that (only internally, from decQuantizeOp and */
+/* decSetSubnormal) the value of set->digits may be less than one, */
+/* indicating a round to left. This routine handles that case */
+/* correctly; caller ensures space. */
+/* */
+/* dn->digits, dn->lsu (and as required), and dn->exponent are */
+/* updated as necessary. dn->bits (sign) is unchanged. */
+/* */
+/* DEC_Rounded status is set if any digits are discarded. */
+/* DEC_Inexact status is set if any non-zero digits are discarded, or */
+/* incoming residue was non-0 (implies rounded) */
+/* ------------------------------------------------------------------ */
+/* mapping array: maps 0-9 to canonical residues, so that a residue */
+/* can be adjusted in the range [-1, +1] and achieve correct rounding */
+/* 0 1 2 3 4 5 6 7 8 9 */
+static const uByte resmap[10]={0, 3, 3, 3, 3, 5, 7, 7, 7, 7};
+static void decSetCoeff(decNumber *dn, decContext *set, const Unit *lsu,
+ Int len, Int *residue, uInt *status) {
+ Int discard; /* number of digits to discard */
+ uInt cut; /* cut point in Unit */
+ const Unit *up; /* work */
+ Unit *target; /* .. */
+ Int count; /* .. */
+ #if DECDPUN<=4
+ uInt temp; /* .. */
+ #endif
+
+ discard=len-set->digits; /* digits to discard */
+ if (discard<=0) { /* no digits are being discarded */
+ if (dn->lsu!=lsu) { /* copy needed */
+ /* copy the coefficient array to the result number; no shift needed */
+ count=len; /* avoids D2U */
+ up=lsu;
+ for (target=dn->lsu; count>0; target++, up++, count-=DECDPUN)
+ *target=*up;
+ dn->digits=len; /* set the new length */
+ }
+ /* dn->exponent and residue are unchanged, record any inexactitude */
+ if (*residue!=0) *status|=(DEC_Inexact | DEC_Rounded);
+ return;
+ }
+
+ /* some digits must be discarded ... */
+ dn->exponent+=discard; /* maintain numerical value */
+ *status|=DEC_Rounded; /* accumulate Rounded status */
+ if (*residue>1) *residue=1; /* previous residue now to right, so reduce */
+
+ if (discard>len) { /* everything, +1, is being discarded */
+ /* guard digit is 0 */
+ /* residue is all the number [NB could be all 0s] */
+ if (*residue<=0) { /* not already positive */
+ count=len; /* avoids D2U */
+ for (up=lsu; count>0; up++, count-=DECDPUN) if (*up!=0) { /* found non-0 */
+ *residue=1;
+ break; /* no need to check any others */
+ }
+ }
+ if (*residue!=0) *status|=DEC_Inexact; /* record inexactitude */
+ *dn->lsu=0; /* coefficient will now be 0 */
+ dn->digits=1; /* .. */
+ return;
+ } /* total discard */
+
+ /* partial discard [most common case] */
+ /* here, at least the first (most significant) discarded digit exists */
+
+ /* spin up the number, noting residue during the spin, until get to */
+ /* the Unit with the first discarded digit. When reach it, extract */
+ /* it and remember its position */
+ count=0;
+ for (up=lsu;; up++) {
+ count+=DECDPUN;
+ if (count>=discard) break; /* full ones all checked */
+ if (*up!=0) *residue=1;
+ } /* up */
+
+ /* here up -> Unit with first discarded digit */
+ cut=discard-(count-DECDPUN)-1;
+ if (cut==DECDPUN-1) { /* unit-boundary case (fast) */
+ Unit half=(Unit)powers[DECDPUN]>>1;
+ /* set residue directly */
+ if (*up>=half) {
+ if (*up>half) *residue=7;
+ else *residue+=5; /* add sticky bit */
+ }
+ else { /* <half */
+ if (*up!=0) *residue=3; /* [else is 0, leave as sticky bit] */
+ }
+ if (set->digits<=0) { /* special for Quantize/Subnormal :-( */
+ *dn->lsu=0; /* .. result is 0 */
+ dn->digits=1; /* .. */
+ }
+ else { /* shift to least */
+ count=set->digits; /* now digits to end up with */
+ dn->digits=count; /* set the new length */
+ up++; /* move to next */
+ /* on unit boundary, so shift-down copy loop is simple */
+ for (target=dn->lsu; count>0; target++, up++, count-=DECDPUN)
+ *target=*up;
+ }
+ } /* unit-boundary case */
+
+ else { /* discard digit is in low digit(s), and not top digit */
+ uInt discard1; /* first discarded digit */
+ uInt quot, rem; /* for divisions */
+ if (cut==0) quot=*up; /* is at bottom of unit */
+ else /* cut>0 */ { /* it's not at bottom of unit */
+ #if DECDPUN<=4
+ U_ASSERT(/* cut >= 0 &&*/ cut <= 4);
+ quot=QUOT10(*up, cut);
+ rem=*up-quot*powers[cut];
+ #else
+ rem=*up%powers[cut];
+ quot=*up/powers[cut];
+ #endif
+ if (rem!=0) *residue=1;
+ }
+ /* discard digit is now at bottom of quot */
+ #if DECDPUN<=4
+ temp=(quot*6554)>>16; /* fast /10 */
+ /* Vowels algorithm here not a win (9 instructions) */
+ discard1=quot-X10(temp);
+ quot=temp;
+ #else
+ discard1=quot%10;
+ quot=quot/10;
+ #endif
+ /* here, discard1 is the guard digit, and residue is everything */
+ /* else [use mapping array to accumulate residue safely] */
+ *residue+=resmap[discard1];
+ cut++; /* update cut */
+ /* here: up -> Unit of the array with bottom digit */
+ /* cut is the division point for each Unit */
+ /* quot holds the uncut high-order digits for the current unit */
+ if (set->digits<=0) { /* special for Quantize/Subnormal :-( */
+ *dn->lsu=0; /* .. result is 0 */
+ dn->digits=1; /* .. */
+ }
+ else { /* shift to least needed */
+ count=set->digits; /* now digits to end up with */
+ dn->digits=count; /* set the new length */
+ /* shift-copy the coefficient array to the result number */
+ for (target=dn->lsu; ; target++) {
+ *target=(Unit)quot;
+ count-=(DECDPUN-cut);
+ if (count<=0) break;
+ up++;
+ quot=*up;
+ #if DECDPUN<=4
+ quot=QUOT10(quot, cut);
+ rem=*up-quot*powers[cut];
+ #else
+ rem=quot%powers[cut];
+ quot=quot/powers[cut];
+ #endif
+ *target=(Unit)(*target+rem*powers[DECDPUN-cut]);
+ count-=cut;
+ if (count<=0) break;
+ } /* shift-copy loop */
+ } /* shift to least */
+ } /* not unit boundary */
+
+ if (*residue!=0) *status|=DEC_Inexact; /* record inexactitude */
+ return;
+ } /* decSetCoeff */
+
+/* ------------------------------------------------------------------ */
+/* decApplyRound -- apply pending rounding to a number */
+/* */
+/* dn is the number, with space for set->digits digits */
+/* set is the context [for size and rounding mode] */
+/* residue indicates pending rounding, being any accumulated */
+/* guard and sticky information. It may be: */
+/* 6-9: rounding digit is >5 */
+/* 5: rounding digit is exactly half-way */
+/* 1-4: rounding digit is <5 and >0 */
+/* 0: the coefficient is exact */
+/* -1: as 1, but the hidden digits are subtractive, that */
+/* is, of the opposite sign to dn. In this case the */
+/* coefficient must be non-0. This case occurs when */
+/* subtracting a small number (which can be reduced to */
+/* a sticky bit); see decAddOp. */
+/* status is the status accumulator, as usual */
+/* */
+/* This routine applies rounding while keeping the length of the */
+/* coefficient constant. The exponent and status are unchanged */
+/* except if: */
+/* */
+/* -- the coefficient was increased and is all nines (in which */
+/* case Overflow could occur, and is handled directly here so */
+/* the caller does not need to re-test for overflow) */
+/* */
+/* -- the coefficient was decreased and becomes all nines (in which */
+/* case Underflow could occur, and is also handled directly). */
+/* */
+/* All fields in dn are updated as required. */
+/* */
+/* ------------------------------------------------------------------ */
+static void decApplyRound(decNumber *dn, decContext *set, Int residue,
+ uInt *status) {
+ Int bump; /* 1 if coefficient needs to be incremented */
+ /* -1 if coefficient needs to be decremented */
+
+ if (residue==0) return; /* nothing to apply */
+
+ bump=0; /* assume a smooth ride */
+
+ /* now decide whether, and how, to round, depending on mode */
+ switch (set->round) {
+ case DEC_ROUND_05UP: { /* round zero or five up (for reround) */
+ /* This is the same as DEC_ROUND_DOWN unless there is a */
+ /* positive residue and the lsd of dn is 0 or 5, in which case */
+ /* it is bumped; when residue is <0, the number is therefore */
+ /* bumped down unless the final digit was 1 or 6 (in which */
+ /* case it is bumped down and then up -- a no-op) */
+ Int lsd5=*dn->lsu%5; /* get lsd and quintate */
+ if (residue<0 && lsd5!=1) bump=-1;
+ else if (residue>0 && lsd5==0) bump=1;
+ /* [bump==1 could be applied directly; use common path for clarity] */
+ break;} /* r-05 */
+
+ case DEC_ROUND_DOWN: {
+ /* no change, except if negative residue */
+ if (residue<0) bump=-1;
+ break;} /* r-d */
+
+ case DEC_ROUND_HALF_DOWN: {
+ if (residue>5) bump=1;
+ break;} /* r-h-d */
+
+ case DEC_ROUND_HALF_EVEN: {
+ if (residue>5) bump=1; /* >0.5 goes up */
+ else if (residue==5) { /* exactly 0.5000... */
+ /* 0.5 goes up iff [new] lsd is odd */
+ if (*dn->lsu & 0x01) bump=1;
+ }
+ break;} /* r-h-e */
+
+ case DEC_ROUND_HALF_UP: {
+ if (residue>=5) bump=1;
+ break;} /* r-h-u */
+
+ case DEC_ROUND_UP: {
+ if (residue>0) bump=1;
+ break;} /* r-u */
+
+ case DEC_ROUND_CEILING: {
+ /* same as _UP for positive numbers, and as _DOWN for negatives */
+ /* [negative residue cannot occur on 0] */
+ if (decNumberIsNegative(dn)) {
+ if (residue<0) bump=-1;
+ }
+ else {
+ if (residue>0) bump=1;
+ }
+ break;} /* r-c */
+
+ case DEC_ROUND_FLOOR: {
+ /* same as _UP for negative numbers, and as _DOWN for positive */
+ /* [negative residue cannot occur on 0] */
+ if (!decNumberIsNegative(dn)) {
+ if (residue<0) bump=-1;
+ }
+ else {
+ if (residue>0) bump=1;
+ }
+ break;} /* r-f */
+
+ default: { /* e.g., DEC_ROUND_MAX */
+ *status|=DEC_Invalid_context;
+ #if DECTRACE || (DECCHECK && DECVERB)
+ printf("Unknown rounding mode: %d\n", set->round);
+ #endif
+ break;}
+ } /* switch */
+
+ /* now bump the number, up or down, if need be */
+ if (bump==0) return; /* no action required */
+
+ /* Simply use decUnitAddSub unless bumping up and the number is */
+ /* all nines. In this special case set to 100... explicitly */
+ /* and adjust the exponent by one (as otherwise could overflow */
+ /* the array) */
+ /* Similarly handle all-nines result if bumping down. */
+ if (bump>0) {
+ Unit *up; /* work */
+ uInt count=dn->digits; /* digits to be checked */
+ for (up=dn->lsu; ; up++) {
+ if (count<=DECDPUN) {
+ /* this is the last Unit (the msu) */
+ if (*up!=powers[count]-1) break; /* not still 9s */
+ /* here if it, too, is all nines */
+ *up=(Unit)powers[count-1]; /* here 999 -> 100 etc. */
+ for (up=up-1; up>=dn->lsu; up--) *up=0; /* others all to 0 */
+ dn->exponent++; /* and bump exponent */
+ /* [which, very rarely, could cause Overflow...] */
+ if ((dn->exponent+dn->digits)>set->emax+1) {
+ decSetOverflow(dn, set, status);
+ }
+ return; /* done */
+ }
+ /* a full unit to check, with more to come */
+ if (*up!=DECDPUNMAX) break; /* not still 9s */
+ count-=DECDPUN;
+ } /* up */
+ } /* bump>0 */
+ else { /* -1 */
+ /* here checking for a pre-bump of 1000... (leading 1, all */
+ /* other digits zero) */
+ Unit *up, *sup; /* work */
+ uInt count=dn->digits; /* digits to be checked */
+ for (up=dn->lsu; ; up++) {
+ if (count<=DECDPUN) {
+ /* this is the last Unit (the msu) */
+ if (*up!=powers[count-1]) break; /* not 100.. */
+ /* here if have the 1000... case */
+ sup=up; /* save msu pointer */
+ *up=(Unit)powers[count]-1; /* here 100 in msu -> 999 */
+ /* others all to all-nines, too */
+ for (up=up-1; up>=dn->lsu; up--) *up=(Unit)powers[DECDPUN]-1;
+ dn->exponent--; /* and bump exponent */
+
+ /* iff the number was at the subnormal boundary (exponent=etiny) */
+ /* then the exponent is now out of range, so it will in fact get */
+ /* clamped to etiny and the final 9 dropped. */
+ /* printf(">> emin=%d exp=%d sdig=%d\n", set->emin, */
+ /* dn->exponent, set->digits); */
+ if (dn->exponent+1==set->emin-set->digits+1) {
+ if (count==1 && dn->digits==1) *sup=0; /* here 9 -> 0[.9] */
+ else {
+ *sup=(Unit)powers[count-1]-1; /* here 999.. in msu -> 99.. */
+ dn->digits--;
+ }
+ dn->exponent++;
+ *status|=DEC_Underflow | DEC_Subnormal | DEC_Inexact | DEC_Rounded;
+ }
+ return; /* done */
+ }
+
+ /* a full unit to check, with more to come */
+ if (*up!=0) break; /* not still 0s */
+ count-=DECDPUN;
+ } /* up */
+
+ } /* bump<0 */
+
+ /* Actual bump needed. Do it. */
+ decUnitAddSub(dn->lsu, D2U(dn->digits), uarrone, 1, 0, dn->lsu, bump);
+ } /* decApplyRound */
+
+#if DECSUBSET
+/* ------------------------------------------------------------------ */
+/* decFinish -- finish processing a number */
+/* */
+/* dn is the number */
+/* set is the context */
+/* residue is the rounding accumulator (as in decApplyRound) */
+/* status is the accumulator */
+/* */
+/* This finishes off the current number by: */
+/* 1. If not extended: */
+/* a. Converting a zero result to clean '0' */
+/* b. Reducing positive exponents to 0, if would fit in digits */
+/* 2. Checking for overflow and subnormals (always) */
+/* Note this is just Finalize when no subset arithmetic. */
+/* All fields are updated as required. */
+/* ------------------------------------------------------------------ */
+static void decFinish(decNumber *dn, decContext *set, Int *residue,
+ uInt *status) {
+ if (!set->extended) {
+ if ISZERO(dn) { /* value is zero */
+ dn->exponent=0; /* clean exponent .. */
+ dn->bits=0; /* .. and sign */
+ return; /* no error possible */
+ }
+ if (dn->exponent>=0) { /* non-negative exponent */
+ /* >0; reduce to integer if possible */
+ if (set->digits >= (dn->exponent+dn->digits)) {
+ dn->digits=decShiftToMost(dn->lsu, dn->digits, dn->exponent);
+ dn->exponent=0;
+ }
+ }
+ } /* !extended */
+
+ decFinalize(dn, set, residue, status);
+ } /* decFinish */
+#endif
+
+/* ------------------------------------------------------------------ */
+/* decFinalize -- final check, clamp, and round of a number */
+/* */
+/* dn is the number */
+/* set is the context */
+/* residue is the rounding accumulator (as in decApplyRound) */
+/* status is the status accumulator */
+/* */
+/* This finishes off the current number by checking for subnormal */
+/* results, applying any pending rounding, checking for overflow, */
+/* and applying any clamping. */
+/* Underflow and overflow conditions are raised as appropriate. */
+/* All fields are updated as required. */
+/* ------------------------------------------------------------------ */
+static void decFinalize(decNumber *dn, decContext *set, Int *residue,
+ uInt *status) {
+ Int shift; /* shift needed if clamping */
+ Int tinyexp=set->emin-dn->digits+1; /* precalculate subnormal boundary */
+
+ /* Must be careful, here, when checking the exponent as the */
+ /* adjusted exponent could overflow 31 bits [because it may already */
+ /* be up to twice the expected]. */
+
+ /* First test for subnormal. This must be done before any final */
+ /* round as the result could be rounded to Nmin or 0. */
+ if (dn->exponent<=tinyexp) { /* prefilter */
+ Int comp;
+ decNumber nmin;
+ /* A very nasty case here is dn == Nmin and residue<0 */
+ if (dn->exponent<tinyexp) {
+ /* Go handle subnormals; this will apply round if needed. */
+ decSetSubnormal(dn, set, residue, status);
+ return;
+ }
+ /* Equals case: only subnormal if dn=Nmin and negative residue */
+ uprv_decNumberZero(&nmin);
+ nmin.lsu[0]=1;
+ nmin.exponent=set->emin;
+ comp=decCompare(dn, &nmin, 1); /* (signless compare) */
+ if (comp==BADINT) { /* oops */
+ *status|=DEC_Insufficient_storage; /* abandon... */
+ return;
+ }
+ if (*residue<0 && comp==0) { /* neg residue and dn==Nmin */
+ decApplyRound(dn, set, *residue, status); /* might force down */
+ decSetSubnormal(dn, set, residue, status);
+ return;
+ }
+ }
+
+ /* now apply any pending round (this could raise overflow). */
+ if (*residue!=0) decApplyRound(dn, set, *residue, status);
+
+ /* Check for overflow [redundant in the 'rare' case] or clamp */
+ if (dn->exponent<=set->emax-set->digits+1) return; /* neither needed */
+
+
+ /* here when might have an overflow or clamp to do */
+ if (dn->exponent>set->emax-dn->digits+1) { /* too big */
+ decSetOverflow(dn, set, status);
+ return;
+ }
+ /* here when the result is normal but in clamp range */
+ if (!set->clamp) return;
+
+ /* here when need to apply the IEEE exponent clamp (fold-down) */
+ shift=dn->exponent-(set->emax-set->digits+1);
+
+ /* shift coefficient (if non-zero) */
+ if (!ISZERO(dn)) {
+ dn->digits=decShiftToMost(dn->lsu, dn->digits, shift);
+ }
+ dn->exponent-=shift; /* adjust the exponent to match */
+ *status|=DEC_Clamped; /* and record the dirty deed */
+ return;
+ } /* decFinalize */
+
+/* ------------------------------------------------------------------ */
+/* decSetOverflow -- set number to proper overflow value */
+/* */
+/* dn is the number (used for sign [only] and result) */
+/* set is the context [used for the rounding mode, etc.] */
+/* status contains the current status to be updated */
+/* */
+/* This sets the sign of a number and sets its value to either */
+/* Infinity or the maximum finite value, depending on the sign of */
+/* dn and the rounding mode, following IEEE 754 rules. */
+/* ------------------------------------------------------------------ */
+static void decSetOverflow(decNumber *dn, decContext *set, uInt *status) {
+ Flag needmax=0; /* result is maximum finite value */
+ uByte sign=dn->bits&DECNEG; /* clean and save sign bit */
+
+ if (ISZERO(dn)) { /* zero does not overflow magnitude */
+ Int emax=set->emax; /* limit value */
+ if (set->clamp) emax-=set->digits-1; /* lower if clamping */
+ if (dn->exponent>emax) { /* clamp required */
+ dn->exponent=emax;
+ *status|=DEC_Clamped;
+ }
+ return;
+ }
+
+ uprv_decNumberZero(dn);
+ switch (set->round) {
+ case DEC_ROUND_DOWN: {
+ needmax=1; /* never Infinity */
+ break;} /* r-d */
+ case DEC_ROUND_05UP: {
+ needmax=1; /* never Infinity */
+ break;} /* r-05 */
+ case DEC_ROUND_CEILING: {
+ if (sign) needmax=1; /* Infinity if non-negative */
+ break;} /* r-c */
+ case DEC_ROUND_FLOOR: {
+ if (!sign) needmax=1; /* Infinity if negative */
+ break;} /* r-f */
+ default: break; /* Infinity in all other cases */
+ }
+ if (needmax) {
+ decSetMaxValue(dn, set);
+ dn->bits=sign; /* set sign */
+ }
+ else dn->bits=sign|DECINF; /* Value is +/-Infinity */
+ *status|=DEC_Overflow | DEC_Inexact | DEC_Rounded;
+ } /* decSetOverflow */
+
+/* ------------------------------------------------------------------ */
+/* decSetMaxValue -- set number to +Nmax (maximum normal value) */
+/* */
+/* dn is the number to set */
+/* set is the context [used for digits and emax] */
+/* */
+/* This sets the number to the maximum positive value. */
+/* ------------------------------------------------------------------ */
+static void decSetMaxValue(decNumber *dn, decContext *set) {
+ Unit *up; /* work */
+ Int count=set->digits; /* nines to add */
+ dn->digits=count;
+ /* fill in all nines to set maximum value */
+ for (up=dn->lsu; ; up++) {
+ if (count>DECDPUN) *up=DECDPUNMAX; /* unit full o'nines */
+ else { /* this is the msu */
+ *up=(Unit)(powers[count]-1);
+ break;
+ }
+ count-=DECDPUN; /* filled those digits */
+ } /* up */
+ dn->bits=0; /* + sign */
+ dn->exponent=set->emax-set->digits+1;
+ } /* decSetMaxValue */
+
+/* ------------------------------------------------------------------ */
+/* decSetSubnormal -- process value whose exponent is <Emin */
+/* */
+/* dn is the number (used as input as well as output; it may have */
+/* an allowed subnormal value, which may need to be rounded) */
+/* set is the context [used for the rounding mode] */
+/* residue is any pending residue */
+/* status contains the current status to be updated */
+/* */
+/* If subset mode, set result to zero and set Underflow flags. */
+/* */
+/* Value may be zero with a low exponent; this does not set Subnormal */
+/* but the exponent will be clamped to Etiny. */
+/* */
+/* Otherwise ensure exponent is not out of range, and round as */
+/* necessary. Underflow is set if the result is Inexact. */
+/* ------------------------------------------------------------------ */
+static void decSetSubnormal(decNumber *dn, decContext *set, Int *residue,
+ uInt *status) {
+ decContext workset; /* work */
+ Int etiny, adjust; /* .. */
+
+ #if DECSUBSET
+ /* simple set to zero and 'hard underflow' for subset */
+ if (!set->extended) {
+ uprv_decNumberZero(dn);
+ /* always full overflow */
+ *status|=DEC_Underflow | DEC_Subnormal | DEC_Inexact | DEC_Rounded;
+ return;
+ }
+ #endif
+
+ /* Full arithmetic -- allow subnormals, rounded to minimum exponent */
+ /* (Etiny) if needed */
+ etiny=set->emin-(set->digits-1); /* smallest allowed exponent */
+
+ if ISZERO(dn) { /* value is zero */
+ /* residue can never be non-zero here */
+ #if DECCHECK
+ if (*residue!=0) {
+ printf("++ Subnormal 0 residue %ld\n", (LI)*residue);
+ *status|=DEC_Invalid_operation;
+ }
+ #endif
+ if (dn->exponent<etiny) { /* clamp required */
+ dn->exponent=etiny;
+ *status|=DEC_Clamped;
+ }
+ return;
+ }
+
+ *status|=DEC_Subnormal; /* have a non-zero subnormal */
+ adjust=etiny-dn->exponent; /* calculate digits to remove */
+ if (adjust<=0) { /* not out of range; unrounded */
+ /* residue can never be non-zero here, except in the Nmin-residue */
+ /* case (which is a subnormal result), so can take fast-path here */
+ /* it may already be inexact (from setting the coefficient) */
+ if (*status&DEC_Inexact) *status|=DEC_Underflow;
+ return;
+ }
+
+ /* adjust>0, so need to rescale the result so exponent becomes Etiny */
+ /* [this code is similar to that in rescale] */
+ workset=*set; /* clone rounding, etc. */
+ workset.digits=dn->digits-adjust; /* set requested length */
+ workset.emin-=adjust; /* and adjust emin to match */
+ /* [note that the latter can be <1, here, similar to Rescale case] */
+ decSetCoeff(dn, &workset, dn->lsu, dn->digits, residue, status);
+ decApplyRound(dn, &workset, *residue, status);
+
+ /* Use 754 default rule: Underflow is set iff Inexact */
+ /* [independent of whether trapped] */
+ if (*status&DEC_Inexact) *status|=DEC_Underflow;
+
+ /* if rounded up a 999s case, exponent will be off by one; adjust */
+ /* back if so [it will fit, because it was shortened earlier] */
+ if (dn->exponent>etiny) {
+ dn->digits=decShiftToMost(dn->lsu, dn->digits, 1);
+ dn->exponent--; /* (re)adjust the exponent. */
+ }
+
+ /* if rounded to zero, it is by definition clamped... */
+ if (ISZERO(dn)) *status|=DEC_Clamped;
+ } /* decSetSubnormal */
+
+/* ------------------------------------------------------------------ */
+/* decCheckMath - check entry conditions for a math function */
+/* */
+/* This checks the context and the operand */
+/* */
+/* rhs is the operand to check */
+/* set is the context to check */
+/* status is unchanged if both are good */
+/* */
+/* returns non-zero if status is changed, 0 otherwise */
+/* */
+/* Restrictions enforced: */
+/* */
+/* digits, emax, and -emin in the context must be less than */
+/* DEC_MAX_MATH (999999), and A must be within these bounds if */
+/* non-zero. Invalid_operation is set in the status if a */
+/* restriction is violated. */
+/* ------------------------------------------------------------------ */
+static uInt decCheckMath(const decNumber *rhs, decContext *set,
+ uInt *status) {
+ uInt save=*status; /* record */
+ if (set->digits>DEC_MAX_MATH
+ || set->emax>DEC_MAX_MATH
+ || -set->emin>DEC_MAX_MATH) *status|=DEC_Invalid_context;
+ else if ((rhs->digits>DEC_MAX_MATH
+ || rhs->exponent+rhs->digits>DEC_MAX_MATH+1
+ || rhs->exponent+rhs->digits<2*(1-DEC_MAX_MATH))
+ && !ISZERO(rhs)) *status|=DEC_Invalid_operation;
+ return (*status!=save);
+ } /* decCheckMath */
+
+/* ------------------------------------------------------------------ */
+/* decGetInt -- get integer from a number */
+/* */
+/* dn is the number [which will not be altered] */
+/* */
+/* returns one of: */
+/* BADINT if there is a non-zero fraction */
+/* the converted integer */
+/* BIGEVEN if the integer is even and magnitude > 2*10**9 */
+/* BIGODD if the integer is odd and magnitude > 2*10**9 */
+/* */
+/* This checks and gets a whole number from the input decNumber. */
+/* The sign can be determined from dn by the caller when BIGEVEN or */
+/* BIGODD is returned. */
+/* ------------------------------------------------------------------ */
+static Int decGetInt(const decNumber *dn) {
+ Int theInt; /* result accumulator */
+ const Unit *up; /* work */
+ Int got; /* digits (real or not) processed */
+ Int ilength=dn->digits+dn->exponent; /* integral length */
+ Flag neg=decNumberIsNegative(dn); /* 1 if -ve */
+
+ /* The number must be an integer that fits in 10 digits */
+ /* Assert, here, that 10 is enough for any rescale Etiny */
+ #if DEC_MAX_EMAX > 999999999
+ #error GetInt may need updating [for Emax]
+ #endif
+ #if DEC_MIN_EMIN < -999999999
+ #error GetInt may need updating [for Emin]
+ #endif
+ if (ISZERO(dn)) return 0; /* zeros are OK, with any exponent */
+
+ up=dn->lsu; /* ready for lsu */
+ theInt=0; /* ready to accumulate */
+ if (dn->exponent>=0) { /* relatively easy */
+ /* no fractional part [usual]; allow for positive exponent */
+ got=dn->exponent;
+ }
+ else { /* -ve exponent; some fractional part to check and discard */
+ Int count=-dn->exponent; /* digits to discard */
+ /* spin up whole units until reach the Unit with the unit digit */
+ for (; count>=DECDPUN; up++) {
+ if (*up!=0) return BADINT; /* non-zero Unit to discard */
+ count-=DECDPUN;
+ }
+ if (count==0) got=0; /* [a multiple of DECDPUN] */
+ else { /* [not multiple of DECDPUN] */
+ Int rem; /* work */
+ /* slice off fraction digits and check for non-zero */
+ #if DECDPUN<=4
+ theInt=QUOT10(*up, count);
+ rem=*up-theInt*powers[count];
+ #else
+ rem=*up%powers[count]; /* slice off discards */
+ theInt=*up/powers[count];
+ #endif
+ if (rem!=0) return BADINT; /* non-zero fraction */
+ /* it looks good */
+ got=DECDPUN-count; /* number of digits so far */
+ up++; /* ready for next */
+ }
+ }
+ /* now it's known there's no fractional part */
+
+ /* tricky code now, to accumulate up to 9.3 digits */
+ if (got==0) {theInt=*up; got+=DECDPUN; up++;} /* ensure lsu is there */
+
+ if (ilength<11) {
+ Int save=theInt;
+ /* collect any remaining unit(s) */
+ for (; got<ilength; up++) {
+ theInt+=*up*powers[got];
+ got+=DECDPUN;
+ }
+ if (ilength==10) { /* need to check for wrap */
+ if (theInt/(Int)powers[got-DECDPUN]!=(Int)*(up-1)) ilength=11;
+ /* [that test also disallows the BADINT result case] */
+ else if (neg && theInt>1999999997) ilength=11;
+ else if (!neg && theInt>999999999) ilength=11;
+ if (ilength==11) theInt=save; /* restore correct low bit */
+ }
+ }
+
+ if (ilength>10) { /* too big */
+ if (theInt&1) return BIGODD; /* bottom bit 1 */
+ return BIGEVEN; /* bottom bit 0 */
+ }
+
+ if (neg) theInt=-theInt; /* apply sign */
+ return theInt;
+ } /* decGetInt */
+
+/* ------------------------------------------------------------------ */
+/* decDecap -- decapitate the coefficient of a number */
+/* */
+/* dn is the number to be decapitated */
+/* drop is the number of digits to be removed from the left of dn; */
+/* this must be <= dn->digits (if equal, the coefficient is */
+/* set to 0) */
+/* */
+/* Returns dn; dn->digits will be <= the initial digits less drop */
+/* (after removing drop digits there may be leading zero digits */
+/* which will also be removed). Only dn->lsu and dn->digits change. */
+/* ------------------------------------------------------------------ */
+static decNumber *decDecap(decNumber *dn, Int drop) {
+ Unit *msu; /* -> target cut point */
+ Int cut; /* work */
+ if (drop>=dn->digits) { /* losing the whole thing */
+ #if DECCHECK
+ if (drop>dn->digits)
+ printf("decDecap called with drop>digits [%ld>%ld]\n",
+ (LI)drop, (LI)dn->digits);
+ #endif
+ dn->lsu[0]=0;
+ dn->digits=1;
+ return dn;
+ }
+ msu=dn->lsu+D2U(dn->digits-drop)-1; /* -> likely msu */
+ cut=MSUDIGITS(dn->digits-drop); /* digits to be in use in msu */
+ if (cut!=DECDPUN) *msu%=powers[cut]; /* clear left digits */
+ /* that may have left leading zero digits, so do a proper count... */
+ dn->digits=decGetDigits(dn->lsu, static_cast<int32_t>(msu-dn->lsu+1));
+ return dn;
+ } /* decDecap */
+
+/* ------------------------------------------------------------------ */
+/* decBiStr -- compare string with pairwise options */
+/* */
+/* targ is the string to compare */
+/* str1 is one of the strings to compare against (length may be 0) */
+/* str2 is the other; it must be the same length as str1 */
+/* */
+/* returns 1 if strings compare equal, (that is, it is the same */
+/* length as str1 and str2, and each character of targ is in either */
+/* str1 or str2 in the corresponding position), or 0 otherwise */
+/* */
+/* This is used for generic caseless compare, including the awkward */
+/* case of the Turkish dotted and dotless Is. Use as (for example): */
+/* if (decBiStr(test, "mike", "MIKE")) ... */
+/* ------------------------------------------------------------------ */
+static Flag decBiStr(const char *targ, const char *str1, const char *str2) {
+ for (;;targ++, str1++, str2++) {
+ if (*targ!=*str1 && *targ!=*str2) return 0;
+ /* *targ has a match in one (or both, if terminator) */
+ if (*targ=='\0') break;
+ } /* forever */
+ return 1;
+ } /* decBiStr */
+
+/* ------------------------------------------------------------------ */
+/* decNaNs -- handle NaN operand or operands */
+/* */
+/* res is the result number */
+/* lhs is the first operand */
+/* rhs is the second operand, or NULL if none */
+/* context is used to limit payload length */
+/* status contains the current status */
+/* returns res in case convenient */
+/* */
+/* Called when one or both operands is a NaN, and propagates the */
+/* appropriate result to res. When an sNaN is found, it is changed */
+/* to a qNaN and Invalid operation is set. */
+/* ------------------------------------------------------------------ */
+static decNumber * decNaNs(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set,
+ uInt *status) {
+ /* This decision tree ends up with LHS being the source pointer, */
+ /* and status updated if need be */
+ if (lhs->bits & DECSNAN)
+ *status|=DEC_Invalid_operation | DEC_sNaN;
+ else if (rhs==NULL);
+ else if (rhs->bits & DECSNAN) {
+ lhs=rhs;
+ *status|=DEC_Invalid_operation | DEC_sNaN;
+ }
+ else if (lhs->bits & DECNAN);
+ else lhs=rhs;
+
+ /* propagate the payload */
+ if (lhs->digits<=set->digits) uprv_decNumberCopy(res, lhs); /* easy */
+ else { /* too long */
+ const Unit *ul;
+ Unit *ur, *uresp1;
+ /* copy safe number of units, then decapitate */
+ res->bits=lhs->bits; /* need sign etc. */
+ uresp1=res->lsu+D2U(set->digits);
+ for (ur=res->lsu, ul=lhs->lsu; ur<uresp1; ur++, ul++) *ur=*ul;
+ res->digits=D2U(set->digits)*DECDPUN;
+ /* maybe still too long */
+ if (res->digits>set->digits) decDecap(res, res->digits-set->digits);
+ }
+
+ res->bits&=~DECSNAN; /* convert any sNaN to NaN, while */
+ res->bits|=DECNAN; /* .. preserving sign */
+ res->exponent=0; /* clean exponent */
+ /* [coefficient was copied/decapitated] */
+ return res;
+ } /* decNaNs */
+
+/* ------------------------------------------------------------------ */
+/* decStatus -- apply non-zero status */
+/* */
+/* dn is the number to set if error */
+/* status contains the current status (not yet in context) */
+/* set is the context */
+/* */
+/* If the status is an error status, the number is set to a NaN, */
+/* unless the error was an overflow, divide-by-zero, or underflow, */
+/* in which case the number will have already been set. */
+/* */
+/* The context status is then updated with the new status. Note that */
+/* this may raise a signal, so control may never return from this */
+/* routine (hence resources must be recovered before it is called). */
+/* ------------------------------------------------------------------ */
+static void decStatus(decNumber *dn, uInt status, decContext *set) {
+ if (status & DEC_NaNs) { /* error status -> NaN */
+ /* if cause was an sNaN, clear and propagate [NaN is already set up] */
+ if (status & DEC_sNaN) status&=~DEC_sNaN;
+ else {
+ uprv_decNumberZero(dn); /* other error: clean throughout */
+ dn->bits=DECNAN; /* and make a quiet NaN */
+ }
+ }
+ uprv_decContextSetStatus(set, status); /* [may not return] */
+ return;
+ } /* decStatus */
+
+/* ------------------------------------------------------------------ */
+/* decGetDigits -- count digits in a Units array */
+/* */
+/* uar is the Unit array holding the number (this is often an */
+/* accumulator of some sort) */
+/* len is the length of the array in units [>=1] */
+/* */
+/* returns the number of (significant) digits in the array */
+/* */
+/* All leading zeros are excluded, except the last if the array has */
+/* only zero Units. */
+/* ------------------------------------------------------------------ */
+/* This may be called twice during some operations. */
+static Int decGetDigits(Unit *uar, Int len) {
+ Unit *up=uar+(len-1); /* -> msu */
+ Int digits=(len-1)*DECDPUN+1; /* possible digits excluding msu */
+ #if DECDPUN>4
+ uInt const *pow; /* work */
+ #endif
+ /* (at least 1 in final msu) */
+ #if DECCHECK
+ if (len<1) printf("decGetDigits called with len<1 [%ld]\n", (LI)len);
+ #endif
+
+ for (; up>=uar; up--) {
+ if (*up==0) { /* unit is all 0s */
+ if (digits==1) break; /* a zero has one digit */
+ digits-=DECDPUN; /* adjust for 0 unit */
+ continue;}
+ /* found the first (most significant) non-zero Unit */
+ #if DECDPUN>1 /* not done yet */
+ if (*up<10) break; /* is 1-9 */
+ digits++;
+ #if DECDPUN>2 /* not done yet */
+ if (*up<100) break; /* is 10-99 */
+ digits++;
+ #if DECDPUN>3 /* not done yet */
+ if (*up<1000) break; /* is 100-999 */
+ digits++;
+ #if DECDPUN>4 /* count the rest ... */
+ for (pow=&powers[4]; *up>=*pow; pow++) digits++;
+ #endif
+ #endif
+ #endif
+ #endif
+ break;
+ } /* up */
+ return digits;
+ } /* decGetDigits */
+
+#if DECTRACE | DECCHECK
+/* ------------------------------------------------------------------ */
+/* decNumberShow -- display a number [debug aid] */
+/* dn is the number to show */
+/* */
+/* Shows: sign, exponent, coefficient (msu first), digits */
+/* or: sign, special-value */
+/* ------------------------------------------------------------------ */
+/* this is public so other modules can use it */
+void uprv_decNumberShow(const decNumber *dn) {
+ const Unit *up; /* work */
+ uInt u, d; /* .. */
+ Int cut; /* .. */
+ char isign='+'; /* main sign */
+ if (dn==NULL) {
+ printf("NULL\n");
+ return;}
+ if (decNumberIsNegative(dn)) isign='-';
+ printf(" >> %c ", isign);
+ if (dn->bits&DECSPECIAL) { /* Is a special value */
+ if (decNumberIsInfinite(dn)) printf("Infinity");
+ else { /* a NaN */
+ if (dn->bits&DECSNAN) printf("sNaN"); /* signalling NaN */
+ else printf("NaN");
+ }
+ /* if coefficient and exponent are 0, no more to do */
+ if (dn->exponent==0 && dn->digits==1 && *dn->lsu==0) {
+ printf("\n");
+ return;}
+ /* drop through to report other information */
+ printf(" ");
+ }
+
+ /* now carefully display the coefficient */
+ up=dn->lsu+D2U(dn->digits)-1; /* msu */
+ printf("%ld", (LI)*up);
+ for (up=up-1; up>=dn->lsu; up--) {
+ u=*up;
+ printf(":");
+ for (cut=DECDPUN-1; cut>=0; cut--) {
+ d=u/powers[cut];
+ u-=d*powers[cut];
+ printf("%ld", (LI)d);
+ } /* cut */
+ } /* up */
+ if (dn->exponent!=0) {
+ char esign='+';
+ if (dn->exponent<0) esign='-';
+ printf(" E%c%ld", esign, (LI)abs(dn->exponent));
+ }
+ printf(" [%ld]\n", (LI)dn->digits);
+ } /* decNumberShow */
+#endif
+
+#if DECTRACE || DECCHECK
+/* ------------------------------------------------------------------ */
+/* decDumpAr -- display a unit array [debug/check aid] */
+/* name is a single-character tag name */
+/* ar is the array to display */
+/* len is the length of the array in Units */
+/* ------------------------------------------------------------------ */
+static void decDumpAr(char name, const Unit *ar, Int len) {
+ Int i;
+ const char *spec;
+ #if DECDPUN==9
+ spec="%09d ";
+ #elif DECDPUN==8
+ spec="%08d ";
+ #elif DECDPUN==7
+ spec="%07d ";
+ #elif DECDPUN==6
+ spec="%06d ";
+ #elif DECDPUN==5
+ spec="%05d ";
+ #elif DECDPUN==4
+ spec="%04d ";
+ #elif DECDPUN==3
+ spec="%03d ";
+ #elif DECDPUN==2
+ spec="%02d ";
+ #else
+ spec="%d ";
+ #endif
+ printf(" :%c: ", name);
+ for (i=len-1; i>=0; i--) {
+ if (i==len-1) printf("%ld ", (LI)ar[i]);
+ else printf(spec, ar[i]);
+ }
+ printf("\n");
+ return;}
+#endif
+
+#if DECCHECK
+/* ------------------------------------------------------------------ */
+/* decCheckOperands -- check operand(s) to a routine */
+/* res is the result structure (not checked; it will be set to */
+/* quiet NaN if error found (and it is not NULL)) */
+/* lhs is the first operand (may be DECUNRESU) */
+/* rhs is the second (may be DECUNUSED) */
+/* set is the context (may be DECUNCONT) */
+/* returns 0 if both operands, and the context are clean, or 1 */
+/* otherwise (in which case the context will show an error, */
+/* unless NULL). Note that res is not cleaned; caller should */
+/* handle this so res=NULL case is safe. */
+/* The caller is expected to abandon immediately if 1 is returned. */
+/* ------------------------------------------------------------------ */
+static Flag decCheckOperands(decNumber *res, const decNumber *lhs,
+ const decNumber *rhs, decContext *set) {
+ Flag bad=0;
+ if (set==NULL) { /* oops; hopeless */
+ #if DECTRACE || DECVERB
+ printf("Reference to context is NULL.\n");
+ #endif
+ bad=1;
+ return 1;}
+ else if (set!=DECUNCONT
+ && (set->digits<1 || set->round>=DEC_ROUND_MAX)) {
+ bad=1;
+ #if DECTRACE || DECVERB
+ printf("Bad context [digits=%ld round=%ld].\n",
+ (LI)set->digits, (LI)set->round);
+ #endif
+ }
+ else {
+ if (res==NULL) {
+ bad=1;
+ #if DECTRACE
+ /* this one not DECVERB as standard tests include NULL */
+ printf("Reference to result is NULL.\n");
+ #endif
+ }
+ if (!bad && lhs!=DECUNUSED) bad=(decCheckNumber(lhs));
+ if (!bad && rhs!=DECUNUSED) bad=(decCheckNumber(rhs));
+ }
+ if (bad) {
+ if (set!=DECUNCONT) uprv_decContextSetStatus(set, DEC_Invalid_operation);
+ if (res!=DECUNRESU && res!=NULL) {
+ uprv_decNumberZero(res);
+ res->bits=DECNAN; /* qNaN */
+ }
+ }
+ return bad;
+ } /* decCheckOperands */
+
+/* ------------------------------------------------------------------ */
+/* decCheckNumber -- check a number */
+/* dn is the number to check */
+/* returns 0 if the number is clean, or 1 otherwise */
+/* */
+/* The number is considered valid if it could be a result from some */
+/* operation in some valid context. */
+/* ------------------------------------------------------------------ */
+static Flag decCheckNumber(const decNumber *dn) {
+ const Unit *up; /* work */
+ uInt maxuint; /* .. */
+ Int ae, d, digits; /* .. */
+ Int emin, emax; /* .. */
+
+ if (dn==NULL) { /* hopeless */
+ #if DECTRACE
+ /* this one not DECVERB as standard tests include NULL */
+ printf("Reference to decNumber is NULL.\n");
+ #endif
+ return 1;}
+
+ /* check special values */
+ if (dn->bits & DECSPECIAL) {
+ if (dn->exponent!=0) {
+ #if DECTRACE || DECVERB
+ printf("Exponent %ld (not 0) for a special value [%02x].\n",
+ (LI)dn->exponent, dn->bits);
+ #endif
+ return 1;}
+
+ /* 2003.09.08: NaNs may now have coefficients, so next tests Inf only */
+ if (decNumberIsInfinite(dn)) {
+ if (dn->digits!=1) {
+ #if DECTRACE || DECVERB
+ printf("Digits %ld (not 1) for an infinity.\n", (LI)dn->digits);
+ #endif
+ return 1;}
+ if (*dn->lsu!=0) {
+ #if DECTRACE || DECVERB
+ printf("LSU %ld (not 0) for an infinity.\n", (LI)*dn->lsu);
+ #endif
+ decDumpAr('I', dn->lsu, D2U(dn->digits));
+ return 1;}
+ } /* Inf */
+ /* 2002.12.26: negative NaNs can now appear through proposed IEEE */
+ /* concrete formats (decimal64, etc.). */
+ return 0;
+ }
+
+ /* check the coefficient */
+ if (dn->digits<1 || dn->digits>DECNUMMAXP) {
+ #if DECTRACE || DECVERB
+ printf("Digits %ld in number.\n", (LI)dn->digits);
+ #endif
+ return 1;}
+
+ d=dn->digits;
+
+ for (up=dn->lsu; d>0; up++) {
+ if (d>DECDPUN) maxuint=DECDPUNMAX;
+ else { /* reached the msu */
+ maxuint=powers[d]-1;
+ if (dn->digits>1 && *up<powers[d-1]) {
+ #if DECTRACE || DECVERB
+ printf("Leading 0 in number.\n");
+ uprv_decNumberShow(dn);
+ #endif
+ return 1;}
+ }
+ if (*up>maxuint) {
+ #if DECTRACE || DECVERB
+ printf("Bad Unit [%08lx] in %ld-digit number at offset %ld [maxuint %ld].\n",
+ (LI)*up, (LI)dn->digits, (LI)(up-dn->lsu), (LI)maxuint);
+ #endif
+ return 1;}
+ d-=DECDPUN;
+ }
+
+ /* check the exponent. Note that input operands can have exponents */
+ /* which are out of the set->emin/set->emax and set->digits range */
+ /* (just as they can have more digits than set->digits). */
+ ae=dn->exponent+dn->digits-1; /* adjusted exponent */
+ emax=DECNUMMAXE;
+ emin=DECNUMMINE;
+ digits=DECNUMMAXP;
+ if (ae<emin-(digits-1)) {
+ #if DECTRACE || DECVERB
+ printf("Adjusted exponent underflow [%ld].\n", (LI)ae);
+ uprv_decNumberShow(dn);
+ #endif
+ return 1;}
+ if (ae>+emax) {
+ #if DECTRACE || DECVERB
+ printf("Adjusted exponent overflow [%ld].\n", (LI)ae);
+ uprv_decNumberShow(dn);
+ #endif
+ return 1;}
+
+ return 0; /* it's OK */
+ } /* decCheckNumber */
+
+/* ------------------------------------------------------------------ */
+/* decCheckInexact -- check a normal finite inexact result has digits */
+/* dn is the number to check */
+/* set is the context (for status and precision) */
+/* sets Invalid operation, etc., if some digits are missing */
+/* [this check is not made for DECSUBSET compilation or when */
+/* subnormal is not set] */
+/* ------------------------------------------------------------------ */
+static void decCheckInexact(const decNumber *dn, decContext *set) {
+ #if !DECSUBSET && DECEXTFLAG
+ if ((set->status & (DEC_Inexact|DEC_Subnormal))==DEC_Inexact
+ && (set->digits!=dn->digits) && !(dn->bits & DECSPECIAL)) {
+ #if DECTRACE || DECVERB
+ printf("Insufficient digits [%ld] on normal Inexact result.\n",
+ (LI)dn->digits);
+ uprv_decNumberShow(dn);
+ #endif
+ uprv_decContextSetStatus(set, DEC_Invalid_operation);
+ }
+ #else
+ /* next is a noop for quiet compiler */
+ if (dn!=NULL && dn->digits==0) set->status|=DEC_Invalid_operation;
+ #endif
+ return;
+ } /* decCheckInexact */
+#endif
+
+#if DECALLOC
+#undef malloc
+#undef free
+/* ------------------------------------------------------------------ */
+/* decMalloc -- accountable allocation routine */
+/* n is the number of bytes to allocate */
+/* */
+/* Semantics is the same as the stdlib malloc routine, but bytes */
+/* allocated are accounted for globally, and corruption fences are */
+/* added before and after the 'actual' storage. */
+/* ------------------------------------------------------------------ */
+/* This routine allocates storage with an extra twelve bytes; 8 are */
+/* at the start and hold: */
+/* 0-3 the original length requested */
+/* 4-7 buffer corruption detection fence (DECFENCE, x4) */
+/* The 4 bytes at the end also hold a corruption fence (DECFENCE, x4) */
+/* ------------------------------------------------------------------ */
+static void *decMalloc(size_t n) {
+ uInt size=n+12; /* true size */
+ void *alloc; /* -> allocated storage */
+ uByte *b, *b0; /* work */
+ uInt uiwork; /* for macros */
+
+ alloc=malloc(size); /* -> allocated storage */
+ if (alloc==NULL) return NULL; /* out of strorage */
+ b0=(uByte *)alloc; /* as bytes */
+ decAllocBytes+=n; /* account for storage */
+ UBFROMUI(alloc, n); /* save n */
+ /* printf(" alloc ++ dAB: %ld (%ld)\n", (LI)decAllocBytes, (LI)n); */
+ for (b=b0+4; b<b0+8; b++) *b=DECFENCE;
+ for (b=b0+n+8; b<b0+n+12; b++) *b=DECFENCE;
+ return b0+8; /* -> play area */
+ } /* decMalloc */
+
+/* ------------------------------------------------------------------ */
+/* decFree -- accountable free routine */
+/* alloc is the storage to free */
+/* */
+/* Semantics is the same as the stdlib malloc routine, except that */
+/* the global storage accounting is updated and the fences are */
+/* checked to ensure that no routine has written 'out of bounds'. */
+/* ------------------------------------------------------------------ */
+/* This routine first checks that the fences have not been corrupted. */
+/* It then frees the storage using the 'truw' storage address (that */
+/* is, offset by 8). */
+/* ------------------------------------------------------------------ */
+static void decFree(void *alloc) {
+ uInt n; /* original length */
+ uByte *b, *b0; /* work */
+ uInt uiwork; /* for macros */
+
+ if (alloc==NULL) return; /* allowed; it's a nop */
+ b0=(uByte *)alloc; /* as bytes */
+ b0-=8; /* -> true start of storage */
+ n=UBTOUI(b0); /* lift length */
+ for (b=b0+4; b<b0+8; b++) if (*b!=DECFENCE)
+ printf("=== Corrupt byte [%02x] at offset %d from %ld ===\n", *b,
+ b-b0-8, (LI)b0);
+ for (b=b0+n+8; b<b0+n+12; b++) if (*b!=DECFENCE)
+ printf("=== Corrupt byte [%02x] at offset +%d from %ld, n=%ld ===\n", *b,
+ b-b0-8, (LI)b0, (LI)n);
+ free(b0); /* drop the storage */
+ decAllocBytes-=n; /* account for storage */
+ /* printf(" free -- dAB: %d (%d)\n", decAllocBytes, -n); */
+ } /* decFree */
+#define malloc(a) decMalloc(a)
+#define free(a) decFree(a)
+#endif
diff --git a/contrib/libs/icu/i18n/decNumber.h b/contrib/libs/icu/i18n/decNumber.h
index 7182e789e5..e23dc438fc 100644
--- a/contrib/libs/icu/i18n/decNumber.h
+++ b/contrib/libs/icu/i18n/decNumber.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/* ------------------------------------------------------------------ */
/* Decimal Number arithmetic module header */
diff --git a/contrib/libs/icu/i18n/decNumberLocal.h b/contrib/libs/icu/i18n/decNumberLocal.h
index e8d1b38653..9a0f56a81e 100644
--- a/contrib/libs/icu/i18n/decNumberLocal.h
+++ b/contrib/libs/icu/i18n/decNumberLocal.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/* ------------------------------------------------------------------ */
/* decNumber package local type, tuning, and macro definitions */
@@ -166,9 +166,9 @@
/* Set DECDPUNMAX -- the maximum integer that fits in DECDPUN */
/* digits, and D2UTABLE -- the initializer for the D2U table */
- #ifndef DECDPUN
- // no-op
- #elif DECDPUN==1
+ #ifndef DECDPUN
+ // no-op
+ #elif DECDPUN==1
#define DECDPUNMAX 9
#define D2UTABLE {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17, \
18,19,20,21,22,23,24,25,26,27,28,29,30,31,32, \
@@ -214,7 +214,7 @@
#define D2UTABLE {0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,3,3,3, \
3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5, \
5,5,6,6,6,6}
- #else
+ #else
#error DECDPUN must be in the range 1-9
#endif
@@ -230,9 +230,9 @@
/* D2U -- return the number of Units needed to hold d digits */
/* (runtime version, with table lookaside for small d) */
- #if defined(DECDPUN) && DECDPUN==8
+ #if defined(DECDPUN) && DECDPUN==8
#define D2U(d) ((unsigned)((d)<=DECMAXD2U?d2utable[d]:((d)+7)>>3))
- #elif defined(DECDPUN) && DECDPUN==4
+ #elif defined(DECDPUN) && DECDPUN==4
#define D2U(d) ((unsigned)((d)<=DECMAXD2U?d2utable[d]:((d)+3)>>2))
#else
#define D2U(d) ((d)<=DECMAXD2U?d2utable[d]:((d)+DECDPUN-1)/DECDPUN)
@@ -259,7 +259,7 @@
/* 2,000,000,000 (as is needed for negative exponents of */
/* subnormals). The unsigned integer pow is used as a temporary */
/* variable. */
- #define TODIGIT(u, cut, c, pow) UPRV_BLOCK_MACRO_BEGIN { \
+ #define TODIGIT(u, cut, c, pow) UPRV_BLOCK_MACRO_BEGIN { \
*(c)='0'; \
pow=DECPOWERS[cut]*2; \
if ((u)>pow) { \
@@ -272,7 +272,7 @@
if ((u)>=pow) {(u)-=pow; *(c)+=2;} \
pow/=2; \
if ((u)>=pow) {(u)-=pow; *(c)+=1;} \
- } UPRV_BLOCK_MACRO_END
+ } UPRV_BLOCK_MACRO_END
/* ---------------------------------------------------------------- */
/* Definitions for fixed-precision modules (only valid after */
diff --git a/contrib/libs/icu/i18n/decimfmt.cpp b/contrib/libs/icu/i18n/decimfmt.cpp
index daa1129a6a..8ac9041c2c 100644
--- a/contrib/libs/icu/i18n/decimfmt.cpp
+++ b/contrib/libs/icu/i18n/decimfmt.cpp
@@ -1,1879 +1,1879 @@
-// © 2018 and later: Unicode, Inc. and others.
+// © 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 <cmath>
-#include <cstdlib>
-#include <stdlib.h>
-#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 VS2015 warns C4805 when comparing bool with UBool, VS2017 no longer emits this warning.
-// 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<bool>(b)
+// Allow implicit conversion from char16_t* to UnicodeString for this file:
+// Helpful in toString methods and elsewhere.
+#define UNISTR_FROM_STRING_EXPLICIT
+
+#include <cmath>
+#include <cstdlib>
+#include <stdlib.h>
+#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 VS2015 warns C4805 when comparing bool with UBool, VS2017 no longer emits this warning.
+// 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<bool>(b)
#else
-#define UBOOL_TO_BOOL(b) b
+#define UBOOL_TO_BOOL(b) b
#endif
-UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormat)
-
-
-DecimalFormat::DecimalFormat(UErrorCode& status)
- : DecimalFormat(nullptr, status) {
- if (U_FAILURE(status)) { return; }
- // Use the default locale and decimal pattern.
- const char* localeName = Locale::getDefault().getName();
- LocalPointer<NumberingSystem> 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) {
- if (U_FAILURE(status)) { return; }
- setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
- touch(status);
-}
-
-DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt,
- UErrorCode& status)
- : DecimalFormat(symbolsToAdopt, status) {
- if (U_FAILURE(status)) { return; }
- setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
- touch(status);
-}
-
-DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt,
- UNumberFormatStyle style, UErrorCode& status)
- : DecimalFormat(symbolsToAdopt, status) {
- if (U_FAILURE(status)) { return; }
- // 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 {
- setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, 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<CurrencyPluralInfo> cpi(
- new CurrencyPluralInfo(fields->symbols->getLocale(), status),
- status);
- if (U_FAILURE(status)) { return; }
- fields->properties.currencyPluralInfo.fPtr.adoptInstead(cpi.orphan());
- }
- touch(status);
-}
-
-DecimalFormat::DecimalFormat(const DecimalFormatSymbols* symbolsToAdopt, UErrorCode& status) {
- // we must take ownership of symbolsToAdopt, even in a failure case.
- LocalPointer<const DecimalFormatSymbols> adoptedSymbols(symbolsToAdopt);
- if (U_FAILURE(status)) {
- return;
- }
- fields = new DecimalFormatFields();
- if (fields == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- if (adoptedSymbols.isNull()) {
- fields->symbols.adoptInsteadAndCheckErrorCode(new DecimalFormatSymbols(status), status);
- } else {
- fields->symbols.adoptInsteadAndCheckErrorCode(adoptedSymbols.orphan(), status);
- }
- if (U_FAILURE(status)) {
- delete fields;
- fields = nullptr;
- }
-}
-
-#if UCONFIG_HAVE_PARSEALLINPUT
-
-void DecimalFormat::setParseAllInput(UNumberFormatAttributeValue value) {
- if (fields == nullptr) { return; }
- 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; }
-
- if (fields == nullptr) {
- // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
- status = U_MEMORY_ALLOCATION_ERROR;
- 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_SCALE:
- setMultiplierScale(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;
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormat)
+
+
+DecimalFormat::DecimalFormat(UErrorCode& status)
+ : DecimalFormat(nullptr, status) {
+ if (U_FAILURE(status)) { return; }
+ // Use the default locale and decimal pattern.
+ const char* localeName = Locale::getDefault().getName();
+ LocalPointer<NumberingSystem> 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) {
+ if (U_FAILURE(status)) { return; }
+ setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
+ touch(status);
+}
+
+DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt,
+ UErrorCode& status)
+ : DecimalFormat(symbolsToAdopt, status) {
+ if (U_FAILURE(status)) { return; }
+ setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
+ touch(status);
+}
+
+DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt,
+ UNumberFormatStyle style, UErrorCode& status)
+ : DecimalFormat(symbolsToAdopt, status) {
+ if (U_FAILURE(status)) { return; }
+ // 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 {
+ setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, 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<CurrencyPluralInfo> cpi(
+ new CurrencyPluralInfo(fields->symbols->getLocale(), status),
+ status);
+ if (U_FAILURE(status)) { return; }
+ fields->properties.currencyPluralInfo.fPtr.adoptInstead(cpi.orphan());
+ }
+ touch(status);
+}
+
+DecimalFormat::DecimalFormat(const DecimalFormatSymbols* symbolsToAdopt, UErrorCode& status) {
+ // we must take ownership of symbolsToAdopt, even in a failure case.
+ LocalPointer<const DecimalFormatSymbols> adoptedSymbols(symbolsToAdopt);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fields = new DecimalFormatFields();
+ if (fields == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ if (adoptedSymbols.isNull()) {
+ fields->symbols.adoptInsteadAndCheckErrorCode(new DecimalFormatSymbols(status), status);
+ } else {
+ fields->symbols.adoptInsteadAndCheckErrorCode(adoptedSymbols.orphan(), status);
+ }
+ if (U_FAILURE(status)) {
+ delete fields;
+ fields = nullptr;
+ }
+}
+
+#if UCONFIG_HAVE_PARSEALLINPUT
+
+void DecimalFormat::setParseAllInput(UNumberFormatAttributeValue value) {
+ if (fields == nullptr) { return; }
+ 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; }
+
+ if (fields == nullptr) {
+ // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
+ status = U_MEMORY_ALLOCATION_ERROR;
+ 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_SCALE:
+ setMultiplierScale(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;
+ case UNUM_PARSE_ALL_INPUT:
+ setParseAllInput((UNumberFormatAttributeValue) newValue);
+ break;
#endif
- case UNUM_PARSE_NO_EXPONENT:
- setParseNoExponent((UBool) newValue);
- break;
-
- case UNUM_PARSE_DECIMAL_MARK_REQUIRED:
- setDecimalPatternMatchRequired((UBool) newValue);
- break;
+ case UNUM_PARSE_NO_EXPONENT:
+ setParseNoExponent((UBool) newValue);
+ break;
- case UNUM_CURRENCY_USAGE:
- setCurrencyUsage((UCurrencyUsage) newValue, &status);
- break;
+ case UNUM_PARSE_DECIMAL_MARK_REQUIRED:
+ setDecimalPatternMatchRequired((UBool) newValue);
+ break;
- case UNUM_MINIMUM_GROUPING_DIGITS:
- setMinimumGroupingDigits(newValue);
- break;
+ case UNUM_CURRENCY_USAGE:
+ setCurrencyUsage((UCurrencyUsage) newValue, &status);
+ break;
- case UNUM_PARSE_CASE_SENSITIVE:
- setParseCaseSensitive(static_cast<UBool>(newValue));
- break;
+ case UNUM_MINIMUM_GROUPING_DIGITS:
+ setMinimumGroupingDigits(newValue);
+ break;
- case UNUM_SIGN_ALWAYS_SHOWN:
- setSignAlwaysShown(static_cast<UBool>(newValue));
- break;
+ case UNUM_PARSE_CASE_SENSITIVE:
+ setParseCaseSensitive(static_cast<UBool>(newValue));
+ break;
- case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
- setFormatFailIfMoreThanMaxDigits(static_cast<UBool>(newValue));
- break;
+ case UNUM_SIGN_ALWAYS_SHOWN:
+ setSignAlwaysShown(static_cast<UBool>(newValue));
+ break;
- default:
- status = U_UNSUPPORTED_ERROR;
- break;
- }
- return *this;
-}
-
-int32_t DecimalFormat::getAttribute(UNumberFormatAttribute attr, UErrorCode& status) const {
- if (U_FAILURE(status)) { return -1; }
-
- if (fields == nullptr) {
- // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
+ case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
+ setFormatFailIfMoreThanMaxDigits(static_cast<UBool>(newValue));
+ break;
+
+ default:
+ status = U_UNSUPPORTED_ERROR;
+ break;
+ }
+ return *this;
+}
+
+int32_t DecimalFormat::getAttribute(UNumberFormatAttribute attr, UErrorCode& status) const {
+ if (U_FAILURE(status)) { return -1; }
+
+ if (fields == nullptr) {
+ // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
status = U_MEMORY_ALLOCATION_ERROR;
- return -1;
+ 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();
-
- case UNUM_MAX_INTEGER_DIGITS:
- return getMaximumIntegerDigits();
-
- case UNUM_MIN_INTEGER_DIGITS:
- return getMinimumIntegerDigits();
-
- case UNUM_INTEGER_DIGITS:
- // TBD: what should this return?
- return getMinimumIntegerDigits();
-
- case UNUM_MAX_FRACTION_DIGITS:
- return getMaximumFractionDigits();
-
- case UNUM_MIN_FRACTION_DIGITS:
- return getMinimumFractionDigits();
+ switch (attr) {
+ case UNUM_LENIENT_PARSE:
+ return isLenient();
- case UNUM_FRACTION_DIGITS:
- // TBD: what should this return?
- return getMinimumFractionDigits();
+ case UNUM_PARSE_INT_ONLY:
+ return isParseIntegerOnly();
- case UNUM_SIGNIFICANT_DIGITS_USED:
- return areSignificantDigitsUsed();
+ case UNUM_GROUPING_USED:
+ return isGroupingUsed();
- case UNUM_MAX_SIGNIFICANT_DIGITS:
- return getMaximumSignificantDigits();
+ case UNUM_DECIMAL_ALWAYS_SHOWN:
+ return isDecimalSeparatorAlwaysShown();
- case UNUM_MIN_SIGNIFICANT_DIGITS:
- return getMinimumSignificantDigits();
+ case UNUM_MAX_INTEGER_DIGITS:
+ return getMaximumIntegerDigits();
- case UNUM_MULTIPLIER:
- return getMultiplier();
+ case UNUM_MIN_INTEGER_DIGITS:
+ return getMinimumIntegerDigits();
- case UNUM_SCALE:
- return getMultiplierScale();
+ case UNUM_INTEGER_DIGITS:
+ // TBD: what should this return?
+ return getMinimumIntegerDigits();
- case UNUM_GROUPING_SIZE:
- return getGroupingSize();
+ case UNUM_MAX_FRACTION_DIGITS:
+ return getMaximumFractionDigits();
- case UNUM_ROUNDING_MODE:
- return getRoundingMode();
+ case UNUM_MIN_FRACTION_DIGITS:
+ return getMinimumFractionDigits();
- case UNUM_FORMAT_WIDTH:
- return getFormatWidth();
+ case UNUM_FRACTION_DIGITS:
+ // TBD: what should this return?
+ return getMinimumFractionDigits();
- case UNUM_PADDING_POSITION:
- return getPadPosition();
+ case UNUM_SIGNIFICANT_DIGITS_USED:
+ return areSignificantDigitsUsed();
- case UNUM_SECONDARY_GROUPING_SIZE:
- return getSecondaryGroupingSize();
+ case UNUM_MAX_SIGNIFICANT_DIGITS:
+ return getMaximumSignificantDigits();
- case UNUM_PARSE_NO_EXPONENT:
- return isParseNoExponent();
+ case UNUM_MIN_SIGNIFICANT_DIGITS:
+ return getMinimumSignificantDigits();
- case UNUM_PARSE_DECIMAL_MARK_REQUIRED:
- return isDecimalPatternMatchRequired();
+ case UNUM_MULTIPLIER:
+ return getMultiplier();
- case UNUM_CURRENCY_USAGE:
- return getCurrencyUsage();
+ case UNUM_SCALE:
+ return getMultiplierScale();
- case UNUM_MINIMUM_GROUPING_DIGITS:
- return getMinimumGroupingDigits();
+ case UNUM_GROUPING_SIZE:
+ return getGroupingSize();
- case UNUM_PARSE_CASE_SENSITIVE:
- return isParseCaseSensitive();
+ case UNUM_ROUNDING_MODE:
+ return getRoundingMode();
- case UNUM_SIGN_ALWAYS_SHOWN:
- return isSignAlwaysShown();
+ case UNUM_FORMAT_WIDTH:
+ return getFormatWidth();
- case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
- return isFormatFailIfMoreThanMaxDigits();
+ case UNUM_PADDING_POSITION:
+ return getPadPosition();
- default:
- status = U_UNSUPPORTED_ERROR;
- break;
- }
-
- return -1; /* undefined */
-}
-
-void DecimalFormat::setGroupingUsed(UBool enabled) {
- if (fields == nullptr) {
- return;
- }
- if (UBOOL_TO_BOOL(enabled) == fields->properties.groupingUsed) { return; }
- NumberFormat::setGroupingUsed(enabled); // to set field for compatibility
- fields->properties.groupingUsed = enabled;
- touchNoError();
-}
+ case UNUM_SECONDARY_GROUPING_SIZE:
+ return getSecondaryGroupingSize();
-void DecimalFormat::setParseIntegerOnly(UBool value) {
- if (fields == nullptr) {
- return;
- }
- if (UBOOL_TO_BOOL(value) == fields->properties.parseIntegerOnly) { return; }
- NumberFormat::setParseIntegerOnly(value); // to set field for compatibility
- fields->properties.parseIntegerOnly = value;
- touchNoError();
-}
+ case UNUM_PARSE_NO_EXPONENT:
+ return isParseNoExponent();
-void DecimalFormat::setLenient(UBool enable) {
- if (fields == nullptr) {
- return;
- }
- 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();
-}
-
-DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt,
- UParseError&, UErrorCode& status)
- : DecimalFormat(symbolsToAdopt, status) {
- if (U_FAILURE(status)) { return; }
- // TODO: What is parseError for?
- setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
- touch(status);
-}
-
-DecimalFormat::DecimalFormat(const UnicodeString& pattern, const DecimalFormatSymbols& symbols,
- UErrorCode& status)
- : DecimalFormat(nullptr, status) {
- if (U_FAILURE(status)) { return; }
- LocalPointer<DecimalFormatSymbols> dfs(new DecimalFormatSymbols(symbols), status);
- if (U_FAILURE(status)) {
- // If we failed to allocate DecimalFormatSymbols, then release fields and its members.
- // We must have a fully complete fields object, we cannot have partially populated members.
- delete fields;
- fields = nullptr;
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- fields->symbols.adoptInstead(dfs.orphan());
- setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
- touch(status);
-}
+ case UNUM_PARSE_DECIMAL_MARK_REQUIRED:
+ return isDecimalPatternMatchRequired();
-DecimalFormat::DecimalFormat(const DecimalFormat& source) : NumberFormat(source) {
- // If the object that we are copying from is invalid, no point in going further.
- if (source.fields == nullptr) {
- return;
- }
- // 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(source.fields->properties);
- if (fields == nullptr) {
- return; // no way to report an error.
- }
- UErrorCode status = U_ZERO_ERROR;
- fields->symbols.adoptInsteadAndCheckErrorCode(new DecimalFormatSymbols(*source.fields->symbols), status);
- // In order to simplify error handling logic in the various getters/setters/etc, we do not allow
- // any partially populated DecimalFormatFields object. We must have a fully complete fields object
- // or else we set it to nullptr.
- if (U_FAILURE(status)) {
- delete fields;
- fields = nullptr;
- return;
- }
- touch(status);
-}
+ case UNUM_CURRENCY_USAGE:
+ return getCurrencyUsage();
-DecimalFormat& DecimalFormat::operator=(const DecimalFormat& rhs) {
- // guard against self-assignment
- if (this == &rhs) {
- return *this;
- }
- // Make sure both objects are valid.
- if (fields == nullptr || rhs.fields == nullptr) {
- return *this; // unfortunately, no way to report an error.
- }
- fields->properties = rhs.fields->properties;
- fields->exportedProperties.clear();
- UErrorCode status = U_ZERO_ERROR;
- LocalPointer<DecimalFormatSymbols> dfs(new DecimalFormatSymbols(*rhs.fields->symbols), status);
- if (U_FAILURE(status)) {
- // We failed to allocate DecimalFormatSymbols, release fields and its members.
- // We must have a fully complete fields object, we cannot have partially populated members.
- delete fields;
- fields = nullptr;
- return *this;
- }
- fields->symbols.adoptInstead(dfs.orphan());
- touch(status);
+ case UNUM_MINIMUM_GROUPING_DIGITS:
+ return getMinimumGroupingDigits();
- return *this;
-}
+ case UNUM_PARSE_CASE_SENSITIVE:
+ return isParseCaseSensitive();
-DecimalFormat::~DecimalFormat() {
- if (fields == nullptr) { return; }
+ case UNUM_SIGN_ALWAYS_SHOWN:
+ return isSignAlwaysShown();
- delete fields->atomicParser.exchange(nullptr);
- delete fields->atomicCurrencyParser.exchange(nullptr);
- delete fields;
-}
+ case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
+ return isFormatFailIfMoreThanMaxDigits();
-DecimalFormat* DecimalFormat::clone() const {
- // can only clone valid objects.
- if (fields == nullptr) {
- return nullptr;
- }
- LocalPointer<DecimalFormat> df(new DecimalFormat(*this));
- if (df.isValid() && df->fields != nullptr) {
- return df.orphan();
- }
- return nullptr;
+ default:
+ status = U_UNSUPPORTED_ERROR;
+ break;
+ }
+
+ return -1; /* undefined */
}
-UBool DecimalFormat::operator==(const Format& other) const {
- auto* otherDF = dynamic_cast<const DecimalFormat*>(&other);
- if (otherDF == nullptr) {
- return false;
- }
- // If either object is in an invalid state, prevent dereferencing nullptr below.
- // Additionally, invalid objects should not be considered equal to anything.
- if (fields == nullptr || otherDF->fields == nullptr) {
- return false;
+void DecimalFormat::setGroupingUsed(UBool enabled) {
+ if (fields == nullptr) {
+ return;
}
- return fields->properties == otherDF->fields->properties && *fields->symbols == *otherDF->fields->symbols;
+ if (UBOOL_TO_BOOL(enabled) == fields->properties.groupingUsed) { return; }
+ NumberFormat::setGroupingUsed(enabled); // to set field for compatibility
+ fields->properties.groupingUsed = enabled;
+ touchNoError();
}
-UnicodeString& DecimalFormat::format(double number, UnicodeString& appendTo, FieldPosition& pos) const {
- if (fields == nullptr) {
- appendTo.setToBogus();
- return appendTo;
- }
- if (pos.getField() == FieldPosition::DONT_CARE && fastFormatDouble(number, appendTo)) {
- return appendTo;
- }
- UErrorCode localStatus = U_ZERO_ERROR;
- UFormattedNumberData output;
- output.quantity.setToDouble(number);
- fields->formatter.formatImpl(&output, localStatus);
- fieldPositionHelper(output, pos, appendTo.length(), localStatus);
- auto appendable = UnicodeStringAppendable(appendTo);
- output.appendTo(appendable, localStatus);
- return appendTo;
-}
-
-UnicodeString& DecimalFormat::format(double number, UnicodeString& appendTo, FieldPosition& pos,
- UErrorCode& status) const {
- if (U_FAILURE(status)) {
- return appendTo; // don't overwrite status if it's already a failure.
- }
- if (fields == nullptr) {
- // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
- status = U_MEMORY_ALLOCATION_ERROR;
- appendTo.setToBogus();
- return appendTo;
- }
- if (pos.getField() == FieldPosition::DONT_CARE && fastFormatDouble(number, appendTo)) {
- return appendTo;
- }
- UFormattedNumberData output;
- output.quantity.setToDouble(number);
- fields->formatter.formatImpl(&output, status);
- fieldPositionHelper(output, pos, appendTo.length(), status);
- auto appendable = UnicodeStringAppendable(appendTo);
- output.appendTo(appendable, status);
- return appendTo;
+void DecimalFormat::setParseIntegerOnly(UBool value) {
+ if (fields == nullptr) {
+ return;
+ }
+ if (UBOOL_TO_BOOL(value) == fields->properties.parseIntegerOnly) { return; }
+ NumberFormat::setParseIntegerOnly(value); // to set field for compatibility
+ fields->properties.parseIntegerOnly = value;
+ touchNoError();
}
-UnicodeString&
-DecimalFormat::format(double number, UnicodeString& appendTo, FieldPositionIterator* posIter,
- UErrorCode& status) const {
- if (U_FAILURE(status)) {
- return appendTo; // don't overwrite status if it's already a failure.
- }
- if (fields == nullptr) {
- // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
- status = U_MEMORY_ALLOCATION_ERROR;
- appendTo.setToBogus();
- return appendTo;
- }
- if (posIter == nullptr && fastFormatDouble(number, appendTo)) {
- return appendTo;
+void DecimalFormat::setLenient(UBool enable) {
+ if (fields == nullptr) {
+ return;
}
- UFormattedNumberData output;
- output.quantity.setToDouble(number);
- fields->formatter.formatImpl(&output, status);
- fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
- auto appendable = UnicodeStringAppendable(appendTo);
- output.appendTo(appendable, status);
- return appendTo;
+ 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();
}
-UnicodeString& DecimalFormat::format(int32_t number, UnicodeString& appendTo, FieldPosition& pos) const {
- return format(static_cast<int64_t> (number), appendTo, pos);
-}
-
-UnicodeString& DecimalFormat::format(int32_t number, UnicodeString& appendTo, FieldPosition& pos,
- UErrorCode& status) const {
- return format(static_cast<int64_t> (number), appendTo, pos, status);
-}
-
-UnicodeString&
-DecimalFormat::format(int32_t number, UnicodeString& appendTo, FieldPositionIterator* posIter,
- UErrorCode& status) const {
- return format(static_cast<int64_t> (number), appendTo, posIter, status);
-}
-
-UnicodeString& DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPosition& pos) const {
- if (fields == nullptr) {
- appendTo.setToBogus();
- return appendTo;
- }
- if (pos.getField() == FieldPosition::DONT_CARE && fastFormatInt64(number, appendTo)) {
- return appendTo;
- }
- UErrorCode localStatus = U_ZERO_ERROR;
- UFormattedNumberData output;
- output.quantity.setToLong(number);
- fields->formatter.formatImpl(&output, localStatus);
- fieldPositionHelper(output, pos, appendTo.length(), localStatus);
- auto appendable = UnicodeStringAppendable(appendTo);
- output.appendTo(appendable, localStatus);
- return appendTo;
-}
-
-UnicodeString& DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPosition& pos,
- UErrorCode& status) const {
+DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt,
+ UParseError&, UErrorCode& status)
+ : DecimalFormat(symbolsToAdopt, status) {
+ if (U_FAILURE(status)) { return; }
+ // TODO: What is parseError for?
+ setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
+ touch(status);
+}
+
+DecimalFormat::DecimalFormat(const UnicodeString& pattern, const DecimalFormatSymbols& symbols,
+ UErrorCode& status)
+ : DecimalFormat(nullptr, status) {
+ if (U_FAILURE(status)) { return; }
+ LocalPointer<DecimalFormatSymbols> dfs(new DecimalFormatSymbols(symbols), status);
if (U_FAILURE(status)) {
- return appendTo; // don't overwrite status if it's already a failure.
- }
- if (fields == nullptr) {
- // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
- status = U_MEMORY_ALLOCATION_ERROR;
- appendTo.setToBogus();
- return appendTo;
- }
- if (pos.getField() == FieldPosition::DONT_CARE && fastFormatInt64(number, appendTo)) {
- return appendTo;
- }
- UFormattedNumberData output;
- output.quantity.setToLong(number);
- fields->formatter.formatImpl(&output, status);
- fieldPositionHelper(output, pos, appendTo.length(), status);
- auto appendable = UnicodeStringAppendable(appendTo);
- output.appendTo(appendable, status);
- return appendTo;
-}
-
-UnicodeString&
-DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPositionIterator* posIter,
- UErrorCode& status) const {
+ // If we failed to allocate DecimalFormatSymbols, then release fields and its members.
+ // We must have a fully complete fields object, we cannot have partially populated members.
+ delete fields;
+ fields = nullptr;
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ fields->symbols.adoptInstead(dfs.orphan());
+ setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
+ touch(status);
+}
+
+DecimalFormat::DecimalFormat(const DecimalFormat& source) : NumberFormat(source) {
+ // If the object that we are copying from is invalid, no point in going further.
+ if (source.fields == nullptr) {
+ return;
+ }
+ // 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(source.fields->properties);
+ if (fields == nullptr) {
+ return; // no way to report an error.
+ }
+ UErrorCode status = U_ZERO_ERROR;
+ fields->symbols.adoptInsteadAndCheckErrorCode(new DecimalFormatSymbols(*source.fields->symbols), status);
+ // In order to simplify error handling logic in the various getters/setters/etc, we do not allow
+ // any partially populated DecimalFormatFields object. We must have a fully complete fields object
+ // or else we set it to nullptr.
if (U_FAILURE(status)) {
- return appendTo; // don't overwrite status if it's already a failure.
- }
- if (fields == nullptr) {
- // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
- status = U_MEMORY_ALLOCATION_ERROR;
- appendTo.setToBogus();
- return appendTo;
- }
- if (posIter == nullptr && fastFormatInt64(number, appendTo)) {
- return appendTo;
- }
- UFormattedNumberData output;
- output.quantity.setToLong(number);
- fields->formatter.formatImpl(&output, status);
- fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
- auto appendable = UnicodeStringAppendable(appendTo);
- output.appendTo(appendable, status);
- return appendTo;
+ delete fields;
+ fields = nullptr;
+ return;
+ }
+ touch(status);
+}
+
+DecimalFormat& DecimalFormat::operator=(const DecimalFormat& rhs) {
+ // guard against self-assignment
+ if (this == &rhs) {
+ return *this;
+ }
+ // Make sure both objects are valid.
+ if (fields == nullptr || rhs.fields == nullptr) {
+ return *this; // unfortunately, no way to report an error.
+ }
+ fields->properties = rhs.fields->properties;
+ fields->exportedProperties.clear();
+ UErrorCode status = U_ZERO_ERROR;
+ LocalPointer<DecimalFormatSymbols> dfs(new DecimalFormatSymbols(*rhs.fields->symbols), status);
+ if (U_FAILURE(status)) {
+ // We failed to allocate DecimalFormatSymbols, release fields and its members.
+ // We must have a fully complete fields object, we cannot have partially populated members.
+ delete fields;
+ fields = nullptr;
+ return *this;
+ }
+ fields->symbols.adoptInstead(dfs.orphan());
+ touch(status);
+
+ return *this;
+}
+
+DecimalFormat::~DecimalFormat() {
+ if (fields == nullptr) { return; }
+
+ delete fields->atomicParser.exchange(nullptr);
+ delete fields->atomicCurrencyParser.exchange(nullptr);
+ delete fields;
+}
+
+DecimalFormat* DecimalFormat::clone() const {
+ // can only clone valid objects.
+ if (fields == nullptr) {
+ return nullptr;
+ }
+ LocalPointer<DecimalFormat> df(new DecimalFormat(*this));
+ if (df.isValid() && df->fields != nullptr) {
+ return df.orphan();
+ }
+ return nullptr;
+}
+
+UBool DecimalFormat::operator==(const Format& other) const {
+ auto* otherDF = dynamic_cast<const DecimalFormat*>(&other);
+ if (otherDF == nullptr) {
+ return false;
+ }
+ // If either object is in an invalid state, prevent dereferencing nullptr below.
+ // Additionally, invalid objects should not be considered equal to anything.
+ if (fields == nullptr || otherDF->fields == nullptr) {
+ return false;
+ }
+ return fields->properties == otherDF->fields->properties && *fields->symbols == *otherDF->fields->symbols;
+}
+
+UnicodeString& DecimalFormat::format(double number, UnicodeString& appendTo, FieldPosition& pos) const {
+ if (fields == nullptr) {
+ appendTo.setToBogus();
+ return appendTo;
+ }
+ if (pos.getField() == FieldPosition::DONT_CARE && fastFormatDouble(number, appendTo)) {
+ return appendTo;
+ }
+ UErrorCode localStatus = U_ZERO_ERROR;
+ UFormattedNumberData output;
+ output.quantity.setToDouble(number);
+ fields->formatter.formatImpl(&output, localStatus);
+ fieldPositionHelper(output, pos, appendTo.length(), localStatus);
+ auto appendable = UnicodeStringAppendable(appendTo);
+ output.appendTo(appendable, localStatus);
+ return appendTo;
+}
+
+UnicodeString& DecimalFormat::format(double number, UnicodeString& appendTo, FieldPosition& pos,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return appendTo; // don't overwrite status if it's already a failure.
+ }
+ if (fields == nullptr) {
+ // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
+ status = U_MEMORY_ALLOCATION_ERROR;
+ appendTo.setToBogus();
+ return appendTo;
+ }
+ if (pos.getField() == FieldPosition::DONT_CARE && fastFormatDouble(number, appendTo)) {
+ return appendTo;
+ }
+ UFormattedNumberData output;
+ output.quantity.setToDouble(number);
+ fields->formatter.formatImpl(&output, status);
+ fieldPositionHelper(output, pos, appendTo.length(), status);
+ auto appendable = UnicodeStringAppendable(appendTo);
+ output.appendTo(appendable, status);
+ return appendTo;
}
UnicodeString&
-DecimalFormat::format(StringPiece number, UnicodeString& appendTo, FieldPositionIterator* posIter,
- UErrorCode& status) const {
- if (U_FAILURE(status)) {
- return appendTo; // don't overwrite status if it's already a failure.
- }
- if (fields == nullptr) {
- // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
- status = U_MEMORY_ALLOCATION_ERROR;
- appendTo.setToBogus();
- return appendTo;
- }
- UFormattedNumberData output;
- output.quantity.setToDecNumber(number, status);
- fields->formatter.formatImpl(&output, status);
- fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
- auto appendable = UnicodeStringAppendable(appendTo);
- output.appendTo(appendable, status);
- return appendTo;
-}
-
-UnicodeString& DecimalFormat::format(const DecimalQuantity& number, UnicodeString& appendTo,
- FieldPositionIterator* posIter, UErrorCode& status) const {
- if (U_FAILURE(status)) {
- return appendTo; // don't overwrite status if it's already a failure.
- }
- if (fields == nullptr) {
- // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
- status = U_MEMORY_ALLOCATION_ERROR;
- appendTo.setToBogus();
- return appendTo;
- }
- UFormattedNumberData output;
- output.quantity = number;
- fields->formatter.formatImpl(&output, status);
- fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
- auto appendable = UnicodeStringAppendable(appendTo);
- output.appendTo(appendable, status);
- return appendTo;
+DecimalFormat::format(double number, UnicodeString& appendTo, FieldPositionIterator* posIter,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return appendTo; // don't overwrite status if it's already a failure.
+ }
+ if (fields == nullptr) {
+ // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
+ status = U_MEMORY_ALLOCATION_ERROR;
+ appendTo.setToBogus();
+ return appendTo;
+ }
+ if (posIter == nullptr && fastFormatDouble(number, appendTo)) {
+ return appendTo;
+ }
+ UFormattedNumberData output;
+ output.quantity.setToDouble(number);
+ fields->formatter.formatImpl(&output, status);
+ fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
+ auto appendable = UnicodeStringAppendable(appendTo);
+ output.appendTo(appendable, status);
+ return appendTo;
+}
+
+UnicodeString& DecimalFormat::format(int32_t number, UnicodeString& appendTo, FieldPosition& pos) const {
+ return format(static_cast<int64_t> (number), appendTo, pos);
+}
+
+UnicodeString& DecimalFormat::format(int32_t number, UnicodeString& appendTo, FieldPosition& pos,
+ UErrorCode& status) const {
+ return format(static_cast<int64_t> (number), appendTo, pos, status);
}
UnicodeString&
-DecimalFormat::format(const DecimalQuantity& number, UnicodeString& appendTo, FieldPosition& pos,
- UErrorCode& status) const {
- if (U_FAILURE(status)) {
- return appendTo; // don't overwrite status if it's already a failure.
- }
- if (fields == nullptr) {
- // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
- status = U_MEMORY_ALLOCATION_ERROR;
- appendTo.setToBogus();
- return appendTo;
- }
- UFormattedNumberData output;
- output.quantity = number;
- fields->formatter.formatImpl(&output, status);
- fieldPositionHelper(output, pos, appendTo.length(), status);
- auto appendable = UnicodeStringAppendable(appendTo);
- output.appendTo(appendable, status);
- return appendTo;
-}
-
-void DecimalFormat::parse(const UnicodeString& text, Formattable& output,
- ParsePosition& parsePosition) const {
- if (fields == nullptr) {
- return;
- }
- if (parsePosition.getIndex() < 0 || parsePosition.getIndex() >= text.length()) {
- if (parsePosition.getIndex() == text.length()) {
- // If there is nothing to parse, it is an error
- parsePosition.setErrorIndex(parsePosition.getIndex());
+DecimalFormat::format(int32_t number, UnicodeString& appendTo, FieldPositionIterator* posIter,
+ UErrorCode& status) const {
+ return format(static_cast<int64_t> (number), appendTo, posIter, status);
+}
+
+UnicodeString& DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPosition& pos) const {
+ if (fields == nullptr) {
+ appendTo.setToBogus();
+ return appendTo;
+ }
+ if (pos.getField() == FieldPosition::DONT_CARE && fastFormatInt64(number, appendTo)) {
+ return appendTo;
+ }
+ UErrorCode localStatus = U_ZERO_ERROR;
+ UFormattedNumberData output;
+ output.quantity.setToLong(number);
+ fields->formatter.formatImpl(&output, localStatus);
+ fieldPositionHelper(output, pos, appendTo.length(), localStatus);
+ auto appendable = UnicodeStringAppendable(appendTo);
+ output.appendTo(appendable, localStatus);
+ return appendTo;
+}
+
+UnicodeString& DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPosition& pos,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return appendTo; // don't overwrite status if it's already a failure.
+ }
+ if (fields == nullptr) {
+ // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
+ status = U_MEMORY_ALLOCATION_ERROR;
+ appendTo.setToBogus();
+ return appendTo;
+ }
+ if (pos.getField() == FieldPosition::DONT_CARE && fastFormatInt64(number, appendTo)) {
+ return appendTo;
+ }
+ UFormattedNumberData output;
+ output.quantity.setToLong(number);
+ fields->formatter.formatImpl(&output, status);
+ fieldPositionHelper(output, pos, appendTo.length(), status);
+ auto appendable = UnicodeStringAppendable(appendTo);
+ output.appendTo(appendable, status);
+ return appendTo;
+}
+
+UnicodeString&
+DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPositionIterator* posIter,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return appendTo; // don't overwrite status if it's already a failure.
+ }
+ if (fields == nullptr) {
+ // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
+ status = U_MEMORY_ALLOCATION_ERROR;
+ appendTo.setToBogus();
+ return appendTo;
+ }
+ if (posIter == nullptr && fastFormatInt64(number, appendTo)) {
+ return appendTo;
+ }
+ UFormattedNumberData output;
+ output.quantity.setToLong(number);
+ fields->formatter.formatImpl(&output, status);
+ fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
+ auto appendable = UnicodeStringAppendable(appendTo);
+ output.appendTo(appendable, status);
+ return appendTo;
+}
+
+UnicodeString&
+DecimalFormat::format(StringPiece number, UnicodeString& appendTo, FieldPositionIterator* posIter,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return appendTo; // don't overwrite status if it's already a failure.
+ }
+ if (fields == nullptr) {
+ // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
+ status = U_MEMORY_ALLOCATION_ERROR;
+ appendTo.setToBogus();
+ return appendTo;
+ }
+ UFormattedNumberData output;
+ output.quantity.setToDecNumber(number, status);
+ fields->formatter.formatImpl(&output, status);
+ fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
+ auto appendable = UnicodeStringAppendable(appendTo);
+ output.appendTo(appendable, status);
+ return appendTo;
+}
+
+UnicodeString& DecimalFormat::format(const DecimalQuantity& number, UnicodeString& appendTo,
+ FieldPositionIterator* posIter, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return appendTo; // don't overwrite status if it's already a failure.
+ }
+ if (fields == nullptr) {
+ // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
+ status = U_MEMORY_ALLOCATION_ERROR;
+ appendTo.setToBogus();
+ return appendTo;
+ }
+ UFormattedNumberData output;
+ output.quantity = number;
+ fields->formatter.formatImpl(&output, status);
+ fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
+ auto appendable = UnicodeStringAppendable(appendTo);
+ output.appendTo(appendable, status);
+ return appendTo;
+}
+
+UnicodeString&
+DecimalFormat::format(const DecimalQuantity& number, UnicodeString& appendTo, FieldPosition& pos,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return appendTo; // don't overwrite status if it's already a failure.
+ }
+ if (fields == nullptr) {
+ // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
+ status = U_MEMORY_ALLOCATION_ERROR;
+ appendTo.setToBogus();
+ return appendTo;
+ }
+ UFormattedNumberData output;
+ output.quantity = number;
+ fields->formatter.formatImpl(&output, status);
+ fieldPositionHelper(output, pos, appendTo.length(), status);
+ auto appendable = UnicodeStringAppendable(appendTo);
+ output.appendTo(appendable, status);
+ return appendTo;
+}
+
+void DecimalFormat::parse(const UnicodeString& text, Formattable& output,
+ ParsePosition& parsePosition) const {
+ if (fields == nullptr) {
+ return;
+ }
+ if (parsePosition.getIndex() < 0 || parsePosition.getIndex() >= text.length()) {
+ if (parsePosition.getIndex() == text.length()) {
+ // If there is nothing to parse, it is an error
+ parsePosition.setErrorIndex(parsePosition.getIndex());
}
- return;
- }
-
- 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; // unfortunately no way to report back the error.
- }
- parser->parse(text, startIndex, true, result, status);
- if (U_FAILURE(status)) {
- return; // unfortunately no way to report back the error.
- }
- // 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());
+ return;
+ }
+
+ 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; // unfortunately no way to report back the error.
+ }
+ parser->parse(text, startIndex, true, result, status);
+ if (U_FAILURE(status)) {
+ return; // unfortunately no way to report back the error.
+ }
+ // 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);
- }
-}
-
-CurrencyAmount* DecimalFormat::parseCurrency(const UnicodeString& text, ParsePosition& parsePosition) const {
- if (fields == nullptr) {
- return nullptr;
- }
- if (parsePosition.getIndex() < 0 || parsePosition.getIndex() >= text.length()) {
- return nullptr;
- }
-
- 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);
- if (U_FAILURE(status)) {
- return nullptr;
- }
- // 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());
- LocalPointer<CurrencyAmount> currencyAmount(
- new CurrencyAmount(formattable, result.currencyCode, status), status);
- if (U_FAILURE(status)) {
- return nullptr;
+ parsePosition.setErrorIndex(startIndex + result.charEnd);
+ }
+}
+
+CurrencyAmount* DecimalFormat::parseCurrency(const UnicodeString& text, ParsePosition& parsePosition) const {
+ if (fields == nullptr) {
+ return nullptr;
+ }
+ if (parsePosition.getIndex() < 0 || parsePosition.getIndex() >= text.length()) {
+ return nullptr;
+ }
+
+ 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);
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ // 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());
+ LocalPointer<CurrencyAmount> currencyAmount(
+ new CurrencyAmount(formattable, result.currencyCode, status), status);
+ if (U_FAILURE(status)) {
+ return nullptr;
}
- return currencyAmount.orphan();
- } else {
- parsePosition.setErrorIndex(startIndex + result.charEnd);
- return nullptr;
+ return currencyAmount.orphan();
+ } else {
+ parsePosition.setErrorIndex(startIndex + result.charEnd);
+ return nullptr;
}
}
-const DecimalFormatSymbols* DecimalFormat::getDecimalFormatSymbols(void) const {
- if (fields == nullptr) {
- return nullptr;
+const DecimalFormatSymbols* DecimalFormat::getDecimalFormatSymbols(void) const {
+ if (fields == nullptr) {
+ return nullptr;
}
- return fields->symbols.getAlias();
+ return fields->symbols.getAlias();
}
-void DecimalFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsToAdopt) {
- if (symbolsToAdopt == nullptr) {
- return; // do not allow caller to set fields->symbols to NULL
- }
- // we must take ownership of symbolsToAdopt, even in a failure case.
- LocalPointer<DecimalFormatSymbols> dfs(symbolsToAdopt);
- if (fields == nullptr) {
- return;
+void DecimalFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsToAdopt) {
+ if (symbolsToAdopt == nullptr) {
+ return; // do not allow caller to set fields->symbols to NULL
}
- fields->symbols.adoptInstead(dfs.orphan());
- touchNoError();
-}
+ // we must take ownership of symbolsToAdopt, even in a failure case.
+ LocalPointer<DecimalFormatSymbols> dfs(symbolsToAdopt);
+ if (fields == nullptr) {
+ return;
+ }
+ fields->symbols.adoptInstead(dfs.orphan());
+ touchNoError();
+}
-void DecimalFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols) {
- if (fields == nullptr) {
- return;
+void DecimalFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols) {
+ if (fields == nullptr) {
+ return;
}
- UErrorCode status = U_ZERO_ERROR;
- LocalPointer<DecimalFormatSymbols> dfs(new DecimalFormatSymbols(symbols), status);
- if (U_FAILURE(status)) {
- // We failed to allocate DecimalFormatSymbols, release fields and its members.
- // We must have a fully complete fields object, we cannot have partially populated members.
- delete fields;
- fields = nullptr;
- return;
+ UErrorCode status = U_ZERO_ERROR;
+ LocalPointer<DecimalFormatSymbols> dfs(new DecimalFormatSymbols(symbols), status);
+ if (U_FAILURE(status)) {
+ // We failed to allocate DecimalFormatSymbols, release fields and its members.
+ // We must have a fully complete fields object, we cannot have partially populated members.
+ delete fields;
+ fields = nullptr;
+ return;
}
- fields->symbols.adoptInstead(dfs.orphan());
- touchNoError();
+ fields->symbols.adoptInstead(dfs.orphan());
+ touchNoError();
}
-const CurrencyPluralInfo* DecimalFormat::getCurrencyPluralInfo(void) const {
- if (fields == nullptr) {
- return nullptr;
+const CurrencyPluralInfo* DecimalFormat::getCurrencyPluralInfo(void) const {
+ if (fields == nullptr) {
+ return nullptr;
}
- return fields->properties.currencyPluralInfo.fPtr.getAlias();
+ return fields->properties.currencyPluralInfo.fPtr.getAlias();
}
-void DecimalFormat::adoptCurrencyPluralInfo(CurrencyPluralInfo* toAdopt) {
- // TODO: should we guard against nullptr input, like in adoptDecimalFormatSymbols?
- // we must take ownership of toAdopt, even in a failure case.
- LocalPointer<CurrencyPluralInfo> cpi(toAdopt);
- if (fields == nullptr) {
- return;
+void DecimalFormat::adoptCurrencyPluralInfo(CurrencyPluralInfo* toAdopt) {
+ // TODO: should we guard against nullptr input, like in adoptDecimalFormatSymbols?
+ // we must take ownership of toAdopt, even in a failure case.
+ LocalPointer<CurrencyPluralInfo> cpi(toAdopt);
+ if (fields == nullptr) {
+ return;
}
- fields->properties.currencyPluralInfo.fPtr.adoptInstead(cpi.orphan());
- touchNoError();
+ fields->properties.currencyPluralInfo.fPtr.adoptInstead(cpi.orphan());
+ touchNoError();
}
-void DecimalFormat::setCurrencyPluralInfo(const CurrencyPluralInfo& info) {
- if (fields == nullptr) {
- return;
+void DecimalFormat::setCurrencyPluralInfo(const CurrencyPluralInfo& info) {
+ if (fields == nullptr) {
+ return;
}
- if (fields->properties.currencyPluralInfo.fPtr.isNull()) {
- // Note: clone() can fail with OOM error, but we have no way to report it. :(
- fields->properties.currencyPluralInfo.fPtr.adoptInstead(info.clone());
+ if (fields->properties.currencyPluralInfo.fPtr.isNull()) {
+ // Note: clone() can fail with OOM error, but we have no way to report it. :(
+ fields->properties.currencyPluralInfo.fPtr.adoptInstead(info.clone());
} else {
- *fields->properties.currencyPluralInfo.fPtr = info; // copy-assignment operator
- }
- touchNoError();
-}
+ *fields->properties.currencyPluralInfo.fPtr = info; // copy-assignment operator
+ }
+ touchNoError();
+}
-UnicodeString& DecimalFormat::getPositivePrefix(UnicodeString& result) const {
- if (fields == nullptr) {
- result.setToBogus();
- return result;
+UnicodeString& DecimalFormat::getPositivePrefix(UnicodeString& result) const {
+ if (fields == nullptr) {
+ result.setToBogus();
+ return result;
}
- UErrorCode status = U_ZERO_ERROR;
- fields->formatter.getAffixImpl(true, false, result, status);
- if (U_FAILURE(status)) { result.setToBogus(); }
- return result;
+ UErrorCode status = U_ZERO_ERROR;
+ fields->formatter.getAffixImpl(true, false, result, status);
+ if (U_FAILURE(status)) { result.setToBogus(); }
+ return result;
}
-void DecimalFormat::setPositivePrefix(const UnicodeString& newValue) {
- if (fields == nullptr) {
- return;
- }
- if (newValue == fields->properties.positivePrefix) { return; }
- fields->properties.positivePrefix = newValue;
- touchNoError();
+void DecimalFormat::setPositivePrefix(const UnicodeString& newValue) {
+ if (fields == nullptr) {
+ return;
+ }
+ if (newValue == fields->properties.positivePrefix) { return; }
+ fields->properties.positivePrefix = newValue;
+ touchNoError();
}
-UnicodeString& DecimalFormat::getNegativePrefix(UnicodeString& result) const {
- if (fields == nullptr) {
- result.setToBogus();
- return result;
+UnicodeString& DecimalFormat::getNegativePrefix(UnicodeString& result) const {
+ if (fields == nullptr) {
+ result.setToBogus();
+ return result;
}
- UErrorCode status = U_ZERO_ERROR;
- fields->formatter.getAffixImpl(true, true, result, status);
- if (U_FAILURE(status)) { result.setToBogus(); }
- return result;
+ UErrorCode status = U_ZERO_ERROR;
+ fields->formatter.getAffixImpl(true, true, result, status);
+ if (U_FAILURE(status)) { result.setToBogus(); }
+ return result;
}
-void DecimalFormat::setNegativePrefix(const UnicodeString& newValue) {
- if (fields == nullptr) {
- return;
+void DecimalFormat::setNegativePrefix(const UnicodeString& newValue) {
+ if (fields == nullptr) {
+ return;
}
- if (newValue == fields->properties.negativePrefix) { return; }
- fields->properties.negativePrefix = newValue;
- touchNoError();
+ if (newValue == fields->properties.negativePrefix) { return; }
+ fields->properties.negativePrefix = newValue;
+ touchNoError();
}
-UnicodeString& DecimalFormat::getPositiveSuffix(UnicodeString& result) const {
- if (fields == nullptr) {
- result.setToBogus();
- return result;
+UnicodeString& DecimalFormat::getPositiveSuffix(UnicodeString& result) const {
+ if (fields == nullptr) {
+ result.setToBogus();
+ return result;
}
- UErrorCode status = U_ZERO_ERROR;
- fields->formatter.getAffixImpl(false, false, result, status);
- if (U_FAILURE(status)) { result.setToBogus(); }
- return result;
+ UErrorCode status = U_ZERO_ERROR;
+ fields->formatter.getAffixImpl(false, false, result, status);
+ if (U_FAILURE(status)) { result.setToBogus(); }
+ return result;
}
-void DecimalFormat::setPositiveSuffix(const UnicodeString& newValue) {
- if (fields == nullptr) {
- return;
+void DecimalFormat::setPositiveSuffix(const UnicodeString& newValue) {
+ if (fields == nullptr) {
+ return;
}
- if (newValue == fields->properties.positiveSuffix) { return; }
- fields->properties.positiveSuffix = newValue;
- touchNoError();
+ if (newValue == fields->properties.positiveSuffix) { return; }
+ fields->properties.positiveSuffix = newValue;
+ touchNoError();
}
-UnicodeString& DecimalFormat::getNegativeSuffix(UnicodeString& result) const {
- if (fields == nullptr) {
- result.setToBogus();
- return result;
+UnicodeString& DecimalFormat::getNegativeSuffix(UnicodeString& result) const {
+ if (fields == nullptr) {
+ result.setToBogus();
+ return result;
}
- UErrorCode status = U_ZERO_ERROR;
- fields->formatter.getAffixImpl(false, true, result, status);
- if (U_FAILURE(status)) { result.setToBogus(); }
- return result;
+ UErrorCode status = U_ZERO_ERROR;
+ fields->formatter.getAffixImpl(false, true, result, status);
+ if (U_FAILURE(status)) { result.setToBogus(); }
+ return result;
}
-void DecimalFormat::setNegativeSuffix(const UnicodeString& newValue) {
- if (fields == nullptr) {
- return;
+void DecimalFormat::setNegativeSuffix(const UnicodeString& newValue) {
+ if (fields == nullptr) {
+ return;
}
- if (newValue == fields->properties.negativeSuffix) { return; }
- fields->properties.negativeSuffix = newValue;
- touchNoError();
+ if (newValue == fields->properties.negativeSuffix) { return; }
+ fields->properties.negativeSuffix = newValue;
+ touchNoError();
}
-UBool DecimalFormat::isSignAlwaysShown() const {
- // Not much we can do to report an error.
- if (fields == nullptr) {
- return DecimalFormatProperties::getDefault().signAlwaysShown;
+UBool DecimalFormat::isSignAlwaysShown() const {
+ // Not much we can do to report an error.
+ if (fields == nullptr) {
+ return DecimalFormatProperties::getDefault().signAlwaysShown;
}
- return fields->properties.signAlwaysShown;
+ return fields->properties.signAlwaysShown;
}
-void DecimalFormat::setSignAlwaysShown(UBool value) {
- if (fields == nullptr) { return; }
- if (UBOOL_TO_BOOL(value) == fields->properties.signAlwaysShown) { return; }
- fields->properties.signAlwaysShown = value;
- touchNoError();
+void DecimalFormat::setSignAlwaysShown(UBool value) {
+ if (fields == nullptr) { return; }
+ if (UBOOL_TO_BOOL(value) == fields->properties.signAlwaysShown) { return; }
+ fields->properties.signAlwaysShown = value;
+ touchNoError();
}
-int32_t DecimalFormat::getMultiplier(void) const {
- const DecimalFormatProperties *dfp;
- // Not much we can do to report an error.
- if (fields == nullptr) {
- // Fallback to using the default instance of DecimalFormatProperties.
- dfp = &(DecimalFormatProperties::getDefault());
- } else {
- dfp = &fields->properties;
- }
- if (dfp->multiplier != 1) {
- return dfp->multiplier;
- } else if (dfp->magnitudeMultiplier != 0) {
- return static_cast<int32_t>(uprv_pow10(dfp->magnitudeMultiplier));
+int32_t DecimalFormat::getMultiplier(void) const {
+ const DecimalFormatProperties *dfp;
+ // Not much we can do to report an error.
+ if (fields == nullptr) {
+ // Fallback to using the default instance of DecimalFormatProperties.
+ dfp = &(DecimalFormatProperties::getDefault());
} else {
- return 1;
- }
-}
-
-void DecimalFormat::setMultiplier(int32_t multiplier) {
- if (fields == nullptr) {
- return;
- }
- if (multiplier == 0) {
- multiplier = 1; // one being the benign default value for a multiplier.
- }
-
- // 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;
+ dfp = &fields->properties;
+ }
+ if (dfp->multiplier != 1) {
+ return dfp->multiplier;
+ } else if (dfp->magnitudeMultiplier != 0) {
+ return static_cast<int32_t>(uprv_pow10(dfp->magnitudeMultiplier));
+ } else {
+ return 1;
+ }
+}
+
+void DecimalFormat::setMultiplier(int32_t multiplier) {
+ if (fields == nullptr) {
+ return;
+ }
+ if (multiplier == 0) {
+ multiplier = 1; // one being the benign default value for a multiplier.
+ }
+
+ // 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;
}
- value = temp;
+ value = temp;
}
- if (delta != -1) {
- fields->properties.magnitudeMultiplier = delta;
- fields->properties.multiplier = 1;
- } else {
- fields->properties.magnitudeMultiplier = 0;
- fields->properties.multiplier = multiplier;
- }
- touchNoError();
+ if (delta != -1) {
+ fields->properties.magnitudeMultiplier = delta;
+ fields->properties.multiplier = 1;
+ } else {
+ fields->properties.magnitudeMultiplier = 0;
+ fields->properties.multiplier = multiplier;
+ }
+ touchNoError();
}
-int32_t DecimalFormat::getMultiplierScale() const {
- // Not much we can do to report an error.
- if (fields == nullptr) {
- // Fallback to using the default instance of DecimalFormatProperties.
- return DecimalFormatProperties::getDefault().multiplierScale;
- }
- return fields->properties.multiplierScale;
+int32_t DecimalFormat::getMultiplierScale() const {
+ // Not much we can do to report an error.
+ if (fields == nullptr) {
+ // Fallback to using the default instance of DecimalFormatProperties.
+ return DecimalFormatProperties::getDefault().multiplierScale;
+ }
+ return fields->properties.multiplierScale;
}
-void DecimalFormat::setMultiplierScale(int32_t newValue) {
- if (fields == nullptr) { return; }
- if (newValue == fields->properties.multiplierScale) { return; }
- fields->properties.multiplierScale = newValue;
- touchNoError();
+void DecimalFormat::setMultiplierScale(int32_t newValue) {
+ if (fields == nullptr) { return; }
+ if (newValue == fields->properties.multiplierScale) { return; }
+ fields->properties.multiplierScale = newValue;
+ touchNoError();
}
-double DecimalFormat::getRoundingIncrement(void) const {
- // Not much we can do to report an error.
- if (fields == nullptr) {
- // Fallback to using the default instance of DecimalFormatProperties.
- return DecimalFormatProperties::getDefault().roundingIncrement;
- }
- return fields->exportedProperties.roundingIncrement;
+double DecimalFormat::getRoundingIncrement(void) const {
+ // Not much we can do to report an error.
+ if (fields == nullptr) {
+ // Fallback to using the default instance of DecimalFormatProperties.
+ return DecimalFormatProperties::getDefault().roundingIncrement;
+ }
+ return fields->exportedProperties.roundingIncrement;
}
void DecimalFormat::setRoundingIncrement(double newValue) {
- if (fields == nullptr) { return; }
- if (newValue == fields->properties.roundingIncrement) { return; }
- fields->properties.roundingIncrement = newValue;
- touchNoError();
+ if (fields == nullptr) { return; }
+ if (newValue == fields->properties.roundingIncrement) { return; }
+ fields->properties.roundingIncrement = newValue;
+ touchNoError();
}
-ERoundingMode DecimalFormat::getRoundingMode(void) const {
- // Not much we can do to report an error.
- if (fields == nullptr) {
- // Fallback to using the default instance of DecimalFormatProperties.
- return static_cast<ERoundingMode>(DecimalFormatProperties::getDefault().roundingMode.getNoError());
- }
- // UNumberFormatRoundingMode and ERoundingMode have the same values.
- return static_cast<ERoundingMode>(fields->exportedProperties.roundingMode.getNoError());
+ERoundingMode DecimalFormat::getRoundingMode(void) const {
+ // Not much we can do to report an error.
+ if (fields == nullptr) {
+ // Fallback to using the default instance of DecimalFormatProperties.
+ return static_cast<ERoundingMode>(DecimalFormatProperties::getDefault().roundingMode.getNoError());
+ }
+ // UNumberFormatRoundingMode and ERoundingMode have the same values.
+ return static_cast<ERoundingMode>(fields->exportedProperties.roundingMode.getNoError());
}
void DecimalFormat::setRoundingMode(ERoundingMode roundingMode) {
- if (fields == nullptr) { return; }
- auto uRoundingMode = static_cast<UNumberFormatRoundingMode>(roundingMode);
- if (!fields->properties.roundingMode.isNull() && uRoundingMode == fields->properties.roundingMode.getNoError()) {
- return;
- }
- NumberFormat::setMaximumIntegerDigits(roundingMode); // to set field for compatibility
- fields->properties.roundingMode = uRoundingMode;
- touchNoError();
+ if (fields == nullptr) { return; }
+ auto uRoundingMode = static_cast<UNumberFormatRoundingMode>(roundingMode);
+ if (!fields->properties.roundingMode.isNull() && uRoundingMode == fields->properties.roundingMode.getNoError()) {
+ return;
+ }
+ NumberFormat::setMaximumIntegerDigits(roundingMode); // to set field for compatibility
+ fields->properties.roundingMode = uRoundingMode;
+ touchNoError();
}
-int32_t DecimalFormat::getFormatWidth(void) const {
- // Not much we can do to report an error.
- if (fields == nullptr) {
- // Fallback to using the default instance of DecimalFormatProperties.
- return DecimalFormatProperties::getDefault().formatWidth;
- }
- return fields->properties.formatWidth;
+int32_t DecimalFormat::getFormatWidth(void) const {
+ // Not much we can do to report an error.
+ if (fields == nullptr) {
+ // Fallback to using the default instance of DecimalFormatProperties.
+ return DecimalFormatProperties::getDefault().formatWidth;
+ }
+ return fields->properties.formatWidth;
}
void DecimalFormat::setFormatWidth(int32_t width) {
- if (fields == nullptr) { return; }
- if (width == fields->properties.formatWidth) { return; }
- fields->properties.formatWidth = width;
- touchNoError();
+ if (fields == nullptr) { return; }
+ if (width == fields->properties.formatWidth) { return; }
+ fields->properties.formatWidth = width;
+ touchNoError();
}
UnicodeString DecimalFormat::getPadCharacterString() const {
- if (fields == nullptr || fields->properties.padString.isBogus()) {
- // Readonly-alias the static string kFallbackPaddingString
- return {TRUE, kFallbackPaddingString, -1};
- } else {
- return fields->properties.padString;
- }
+ if (fields == nullptr || fields->properties.padString.isBogus()) {
+ // Readonly-alias the static string kFallbackPaddingString
+ return {TRUE, kFallbackPaddingString, -1};
+ } else {
+ return fields->properties.padString;
+ }
}
-void DecimalFormat::setPadCharacter(const UnicodeString& padChar) {
- if (fields == nullptr) { return; }
- if (padChar == fields->properties.padString) { return; }
+void DecimalFormat::setPadCharacter(const UnicodeString& padChar) {
+ if (fields == nullptr) { return; }
+ if (padChar == fields->properties.padString) { return; }
if (padChar.length() > 0) {
- fields->properties.padString = UnicodeString(padChar.char32At(0));
- } else {
- fields->properties.padString.setToBogus();
+ fields->properties.padString = UnicodeString(padChar.char32At(0));
+ } else {
+ fields->properties.padString.setToBogus();
}
- touchNoError();
+ touchNoError();
}
-EPadPosition DecimalFormat::getPadPosition(void) const {
- if (fields == nullptr || fields->properties.padPosition.isNull()) {
- return EPadPosition::kPadBeforePrefix;
- } else {
- // UNumberFormatPadPosition and EPadPosition have the same values.
- return static_cast<EPadPosition>(fields->properties.padPosition.getNoError());
+EPadPosition DecimalFormat::getPadPosition(void) const {
+ if (fields == nullptr || fields->properties.padPosition.isNull()) {
+ return EPadPosition::kPadBeforePrefix;
+ } else {
+ // UNumberFormatPadPosition and EPadPosition have the same values.
+ return static_cast<EPadPosition>(fields->properties.padPosition.getNoError());
}
}
-void DecimalFormat::setPadPosition(EPadPosition padPos) {
- if (fields == nullptr) { return; }
- auto uPadPos = static_cast<UNumberFormatPadPosition>(padPos);
- if (!fields->properties.padPosition.isNull() && uPadPos == fields->properties.padPosition.getNoError()) {
- return;
- }
- fields->properties.padPosition = uPadPos;
- touchNoError();
+void DecimalFormat::setPadPosition(EPadPosition padPos) {
+ if (fields == nullptr) { return; }
+ auto uPadPos = static_cast<UNumberFormatPadPosition>(padPos);
+ if (!fields->properties.padPosition.isNull() && uPadPos == fields->properties.padPosition.getNoError()) {
+ return;
+ }
+ fields->properties.padPosition = uPadPos;
+ touchNoError();
}
-UBool DecimalFormat::isScientificNotation(void) const {
- // Not much we can do to report an error.
- if (fields == nullptr) {
- // Fallback to using the default instance of DecimalFormatProperties.
- return (DecimalFormatProperties::getDefault().minimumExponentDigits != -1);
+UBool DecimalFormat::isScientificNotation(void) const {
+ // Not much we can do to report an error.
+ if (fields == nullptr) {
+ // Fallback to using the default instance of DecimalFormatProperties.
+ return (DecimalFormatProperties::getDefault().minimumExponentDigits != -1);
}
- return (fields->properties.minimumExponentDigits != -1);
+ return (fields->properties.minimumExponentDigits != -1);
}
void DecimalFormat::setScientificNotation(UBool useScientific) {
- if (fields == nullptr) { return; }
- int32_t minExp = useScientific ? 1 : -1;
- if (fields->properties.minimumExponentDigits == minExp) { return; }
- if (useScientific) {
- fields->properties.minimumExponentDigits = 1;
- } else {
- fields->properties.minimumExponentDigits = -1;
- }
- touchNoError();
-}
-
-int8_t DecimalFormat::getMinimumExponentDigits(void) const {
- // Not much we can do to report an error.
- if (fields == nullptr) {
- // Fallback to using the default instance of DecimalFormatProperties.
- return static_cast<int8_t>(DecimalFormatProperties::getDefault().minimumExponentDigits);
- }
- return static_cast<int8_t>(fields->properties.minimumExponentDigits);
+ if (fields == nullptr) { return; }
+ int32_t minExp = useScientific ? 1 : -1;
+ if (fields->properties.minimumExponentDigits == minExp) { return; }
+ if (useScientific) {
+ fields->properties.minimumExponentDigits = 1;
+ } else {
+ fields->properties.minimumExponentDigits = -1;
+ }
+ touchNoError();
+}
+
+int8_t DecimalFormat::getMinimumExponentDigits(void) const {
+ // Not much we can do to report an error.
+ if (fields == nullptr) {
+ // Fallback to using the default instance of DecimalFormatProperties.
+ return static_cast<int8_t>(DecimalFormatProperties::getDefault().minimumExponentDigits);
+ }
+ return static_cast<int8_t>(fields->properties.minimumExponentDigits);
}
void DecimalFormat::setMinimumExponentDigits(int8_t minExpDig) {
- if (fields == nullptr) { return; }
- if (minExpDig == fields->properties.minimumExponentDigits) { return; }
- fields->properties.minimumExponentDigits = minExpDig;
- touchNoError();
+ if (fields == nullptr) { return; }
+ if (minExpDig == fields->properties.minimumExponentDigits) { return; }
+ fields->properties.minimumExponentDigits = minExpDig;
+ touchNoError();
}
-UBool DecimalFormat::isExponentSignAlwaysShown(void) const {
- // Not much we can do to report an error.
- if (fields == nullptr) {
- // Fallback to using the default instance of DecimalFormatProperties.
- return DecimalFormatProperties::getDefault().exponentSignAlwaysShown;
- }
- return fields->properties.exponentSignAlwaysShown;
+UBool DecimalFormat::isExponentSignAlwaysShown(void) const {
+ // Not much we can do to report an error.
+ if (fields == nullptr) {
+ // Fallback to using the default instance of DecimalFormatProperties.
+ return DecimalFormatProperties::getDefault().exponentSignAlwaysShown;
+ }
+ return fields->properties.exponentSignAlwaysShown;
}
void DecimalFormat::setExponentSignAlwaysShown(UBool expSignAlways) {
- if (fields == nullptr) { return; }
- if (UBOOL_TO_BOOL(expSignAlways) == fields->properties.exponentSignAlwaysShown) { return; }
- fields->properties.exponentSignAlwaysShown = expSignAlways;
- touchNoError();
-}
-
-int32_t DecimalFormat::getGroupingSize(void) const {
- int32_t groupingSize;
- // Not much we can do to report an error.
- if (fields == nullptr) {
- // Fallback to using the default instance of DecimalFormatProperties.
- groupingSize = DecimalFormatProperties::getDefault().groupingSize;
- } else {
- groupingSize = fields->properties.groupingSize;
- }
- if (groupingSize < 0) {
- return 0;
- }
- return groupingSize;
-}
-
-void DecimalFormat::setGroupingSize(int32_t newValue) {
- if (fields == nullptr) { return; }
- if (newValue == fields->properties.groupingSize) { return; }
- fields->properties.groupingSize = newValue;
- touchNoError();
-}
-
-int32_t DecimalFormat::getSecondaryGroupingSize(void) const {
- int32_t grouping2;
- // Not much we can do to report an error.
- if (fields == nullptr) {
- // Fallback to using the default instance of DecimalFormatProperties.
- grouping2 = DecimalFormatProperties::getDefault().secondaryGroupingSize;
- } else {
- grouping2 = fields->properties.secondaryGroupingSize;
- }
- if (grouping2 < 0) {
- return 0;
- }
- return grouping2;
-}
-
-void DecimalFormat::setSecondaryGroupingSize(int32_t newValue) {
- if (fields == nullptr) { return; }
- if (newValue == fields->properties.secondaryGroupingSize) { return; }
- fields->properties.secondaryGroupingSize = newValue;
- touchNoError();
-}
-
-int32_t DecimalFormat::getMinimumGroupingDigits() const {
- // Not much we can do to report an error.
- if (fields == nullptr) {
- // Fallback to using the default instance of DecimalFormatProperties.
- return DecimalFormatProperties::getDefault().minimumGroupingDigits;
- }
- return fields->properties.minimumGroupingDigits;
-}
-
-void DecimalFormat::setMinimumGroupingDigits(int32_t newValue) {
- if (fields == nullptr) { return; }
- if (newValue == fields->properties.minimumGroupingDigits) { return; }
- fields->properties.minimumGroupingDigits = newValue;
- touchNoError();
-}
-
-UBool DecimalFormat::isDecimalSeparatorAlwaysShown(void) const {
- // Not much we can do to report an error.
- if (fields == nullptr) {
- // Fallback to using the default instance of DecimalFormatProperties.
- return DecimalFormatProperties::getDefault().decimalSeparatorAlwaysShown;
- }
- return fields->properties.decimalSeparatorAlwaysShown;
-}
-
-void DecimalFormat::setDecimalSeparatorAlwaysShown(UBool newValue) {
- if (fields == nullptr) { return; }
- if (UBOOL_TO_BOOL(newValue) == fields->properties.decimalSeparatorAlwaysShown) { return; }
- fields->properties.decimalSeparatorAlwaysShown = newValue;
- touchNoError();
-}
-
-UBool DecimalFormat::isDecimalPatternMatchRequired(void) const {
- // Not much we can do to report an error.
- if (fields == nullptr) {
- // Fallback to using the default instance of DecimalFormatProperties.
- return DecimalFormatProperties::getDefault().decimalPatternMatchRequired;
- }
- return fields->properties.decimalPatternMatchRequired;
-}
-
-void DecimalFormat::setDecimalPatternMatchRequired(UBool newValue) {
- if (fields == nullptr) { return; }
- if (UBOOL_TO_BOOL(newValue) == fields->properties.decimalPatternMatchRequired) { return; }
- fields->properties.decimalPatternMatchRequired = newValue;
- touchNoError();
-}
-
-UBool DecimalFormat::isParseNoExponent() const {
- // Not much we can do to report an error.
- if (fields == nullptr) {
- // Fallback to using the default instance of DecimalFormatProperties.
- return DecimalFormatProperties::getDefault().parseNoExponent;
- }
- return fields->properties.parseNoExponent;
-}
-
-void DecimalFormat::setParseNoExponent(UBool value) {
- if (fields == nullptr) { return; }
- if (UBOOL_TO_BOOL(value) == fields->properties.parseNoExponent) { return; }
- fields->properties.parseNoExponent = value;
- touchNoError();
-}
-
-UBool DecimalFormat::isParseCaseSensitive() const {
- // Not much we can do to report an error.
- if (fields == nullptr) {
- // Fallback to using the default instance of DecimalFormatProperties.
- return DecimalFormatProperties::getDefault().parseCaseSensitive;
- }
- return fields->properties.parseCaseSensitive;
-}
-
-void DecimalFormat::setParseCaseSensitive(UBool value) {
- if (fields == nullptr) { return; }
- if (UBOOL_TO_BOOL(value) == fields->properties.parseCaseSensitive) { return; }
- fields->properties.parseCaseSensitive = value;
- touchNoError();
-}
-
-UBool DecimalFormat::isFormatFailIfMoreThanMaxDigits() const {
- // Not much we can do to report an error.
- if (fields == nullptr) {
- // Fallback to using the default instance of DecimalFormatProperties.
- return DecimalFormatProperties::getDefault().formatFailIfMoreThanMaxDigits;
- }
- return fields->properties.formatFailIfMoreThanMaxDigits;
-}
-
-void DecimalFormat::setFormatFailIfMoreThanMaxDigits(UBool value) {
- if (fields == nullptr) { return; }
- if (UBOOL_TO_BOOL(value) == fields->properties.formatFailIfMoreThanMaxDigits) { return; }
- fields->properties.formatFailIfMoreThanMaxDigits = value;
- touchNoError();
-}
-
-UnicodeString& DecimalFormat::toPattern(UnicodeString& result) const {
- if (fields == nullptr) {
- // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
- result.setToBogus();
- return result;
- }
- // 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;
- }
- result = PatternStringUtils::propertiesToPatternString(tprops, localStatus);
- return result;
-}
-
-UnicodeString& DecimalFormat::toLocalizedPattern(UnicodeString& result) const {
- if (fields == nullptr) {
- // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
- result.setToBogus();
- return result;
- }
- ErrorCode localStatus;
- result = toPattern(result);
- result = PatternStringUtils::convertLocalized(result, *fields->symbols, true, localStatus);
- return result;
-}
-
-void DecimalFormat::applyPattern(const UnicodeString& pattern, UParseError&, UErrorCode& status) {
- // TODO: What is parseError for?
- applyPattern(pattern, status);
-}
-
-void DecimalFormat::applyPattern(const UnicodeString& pattern, UErrorCode& status) {
- // don't overwrite status if it's already a failure.
- if (U_FAILURE(status)) { return; }
- if (fields == nullptr) {
- // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- 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& localizedPattern, UErrorCode& status) {
- // don't overwrite status if it's already a failure.
- if (U_FAILURE(status)) { return; }
- if (fields == nullptr) {
- // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- UnicodeString pattern = PatternStringUtils::convertLocalized(
- localizedPattern, *fields->symbols, false, status);
- applyPattern(pattern, status);
+ if (fields == nullptr) { return; }
+ if (UBOOL_TO_BOOL(expSignAlways) == fields->properties.exponentSignAlwaysShown) { return; }
+ fields->properties.exponentSignAlwaysShown = expSignAlways;
+ touchNoError();
+}
+
+int32_t DecimalFormat::getGroupingSize(void) const {
+ int32_t groupingSize;
+ // Not much we can do to report an error.
+ if (fields == nullptr) {
+ // Fallback to using the default instance of DecimalFormatProperties.
+ groupingSize = DecimalFormatProperties::getDefault().groupingSize;
+ } else {
+ groupingSize = fields->properties.groupingSize;
+ }
+ if (groupingSize < 0) {
+ return 0;
+ }
+ return groupingSize;
+}
+
+void DecimalFormat::setGroupingSize(int32_t newValue) {
+ if (fields == nullptr) { return; }
+ if (newValue == fields->properties.groupingSize) { return; }
+ fields->properties.groupingSize = newValue;
+ touchNoError();
+}
+
+int32_t DecimalFormat::getSecondaryGroupingSize(void) const {
+ int32_t grouping2;
+ // Not much we can do to report an error.
+ if (fields == nullptr) {
+ // Fallback to using the default instance of DecimalFormatProperties.
+ grouping2 = DecimalFormatProperties::getDefault().secondaryGroupingSize;
+ } else {
+ grouping2 = fields->properties.secondaryGroupingSize;
+ }
+ if (grouping2 < 0) {
+ return 0;
+ }
+ return grouping2;
+}
+
+void DecimalFormat::setSecondaryGroupingSize(int32_t newValue) {
+ if (fields == nullptr) { return; }
+ if (newValue == fields->properties.secondaryGroupingSize) { return; }
+ fields->properties.secondaryGroupingSize = newValue;
+ touchNoError();
+}
+
+int32_t DecimalFormat::getMinimumGroupingDigits() const {
+ // Not much we can do to report an error.
+ if (fields == nullptr) {
+ // Fallback to using the default instance of DecimalFormatProperties.
+ return DecimalFormatProperties::getDefault().minimumGroupingDigits;
+ }
+ return fields->properties.minimumGroupingDigits;
+}
+
+void DecimalFormat::setMinimumGroupingDigits(int32_t newValue) {
+ if (fields == nullptr) { return; }
+ if (newValue == fields->properties.minimumGroupingDigits) { return; }
+ fields->properties.minimumGroupingDigits = newValue;
+ touchNoError();
+}
+
+UBool DecimalFormat::isDecimalSeparatorAlwaysShown(void) const {
+ // Not much we can do to report an error.
+ if (fields == nullptr) {
+ // Fallback to using the default instance of DecimalFormatProperties.
+ return DecimalFormatProperties::getDefault().decimalSeparatorAlwaysShown;
+ }
+ return fields->properties.decimalSeparatorAlwaysShown;
+}
+
+void DecimalFormat::setDecimalSeparatorAlwaysShown(UBool newValue) {
+ if (fields == nullptr) { return; }
+ if (UBOOL_TO_BOOL(newValue) == fields->properties.decimalSeparatorAlwaysShown) { return; }
+ fields->properties.decimalSeparatorAlwaysShown = newValue;
+ touchNoError();
+}
+
+UBool DecimalFormat::isDecimalPatternMatchRequired(void) const {
+ // Not much we can do to report an error.
+ if (fields == nullptr) {
+ // Fallback to using the default instance of DecimalFormatProperties.
+ return DecimalFormatProperties::getDefault().decimalPatternMatchRequired;
+ }
+ return fields->properties.decimalPatternMatchRequired;
+}
+
+void DecimalFormat::setDecimalPatternMatchRequired(UBool newValue) {
+ if (fields == nullptr) { return; }
+ if (UBOOL_TO_BOOL(newValue) == fields->properties.decimalPatternMatchRequired) { return; }
+ fields->properties.decimalPatternMatchRequired = newValue;
+ touchNoError();
+}
+
+UBool DecimalFormat::isParseNoExponent() const {
+ // Not much we can do to report an error.
+ if (fields == nullptr) {
+ // Fallback to using the default instance of DecimalFormatProperties.
+ return DecimalFormatProperties::getDefault().parseNoExponent;
+ }
+ return fields->properties.parseNoExponent;
+}
+
+void DecimalFormat::setParseNoExponent(UBool value) {
+ if (fields == nullptr) { return; }
+ if (UBOOL_TO_BOOL(value) == fields->properties.parseNoExponent) { return; }
+ fields->properties.parseNoExponent = value;
+ touchNoError();
+}
+
+UBool DecimalFormat::isParseCaseSensitive() const {
+ // Not much we can do to report an error.
+ if (fields == nullptr) {
+ // Fallback to using the default instance of DecimalFormatProperties.
+ return DecimalFormatProperties::getDefault().parseCaseSensitive;
+ }
+ return fields->properties.parseCaseSensitive;
+}
+
+void DecimalFormat::setParseCaseSensitive(UBool value) {
+ if (fields == nullptr) { return; }
+ if (UBOOL_TO_BOOL(value) == fields->properties.parseCaseSensitive) { return; }
+ fields->properties.parseCaseSensitive = value;
+ touchNoError();
+}
+
+UBool DecimalFormat::isFormatFailIfMoreThanMaxDigits() const {
+ // Not much we can do to report an error.
+ if (fields == nullptr) {
+ // Fallback to using the default instance of DecimalFormatProperties.
+ return DecimalFormatProperties::getDefault().formatFailIfMoreThanMaxDigits;
+ }
+ return fields->properties.formatFailIfMoreThanMaxDigits;
+}
+
+void DecimalFormat::setFormatFailIfMoreThanMaxDigits(UBool value) {
+ if (fields == nullptr) { return; }
+ if (UBOOL_TO_BOOL(value) == fields->properties.formatFailIfMoreThanMaxDigits) { return; }
+ fields->properties.formatFailIfMoreThanMaxDigits = value;
+ touchNoError();
+}
+
+UnicodeString& DecimalFormat::toPattern(UnicodeString& result) const {
+ if (fields == nullptr) {
+ // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
+ result.setToBogus();
+ return result;
+ }
+ // 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;
+ }
+ result = PatternStringUtils::propertiesToPatternString(tprops, localStatus);
+ return result;
+}
+
+UnicodeString& DecimalFormat::toLocalizedPattern(UnicodeString& result) const {
+ if (fields == nullptr) {
+ // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
+ result.setToBogus();
+ return result;
+ }
+ ErrorCode localStatus;
+ result = toPattern(result);
+ result = PatternStringUtils::convertLocalized(result, *fields->symbols, true, localStatus);
+ return result;
+}
+
+void DecimalFormat::applyPattern(const UnicodeString& pattern, UParseError&, UErrorCode& status) {
+ // TODO: What is parseError for?
+ applyPattern(pattern, status);
+}
+
+void DecimalFormat::applyPattern(const UnicodeString& pattern, UErrorCode& status) {
+ // don't overwrite status if it's already a failure.
+ if (U_FAILURE(status)) { return; }
+ if (fields == nullptr) {
+ // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ 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& localizedPattern, UErrorCode& status) {
+ // don't overwrite status if it's already a failure.
+ if (U_FAILURE(status)) { return; }
+ if (fields == nullptr) {
+ // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ UnicodeString pattern = PatternStringUtils::convertLocalized(
+ localizedPattern, *fields->symbols, false, status);
+ applyPattern(pattern, status);
}
void DecimalFormat::setMaximumIntegerDigits(int32_t newValue) {
- if (fields == nullptr) { return; }
- 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();
+ if (fields == nullptr) { return; }
+ 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();
}
void DecimalFormat::setMinimumIntegerDigits(int32_t newValue) {
- if (fields == nullptr) { return; }
- 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();
+ if (fields == nullptr) { return; }
+ 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();
}
void DecimalFormat::setMaximumFractionDigits(int32_t newValue) {
- if (fields == nullptr) { return; }
- if (newValue == fields->properties.maximumFractionDigits) { return; }
- // cap for backward compatibility, formerly 340, now 999
- if (newValue > kMaxIntFracSig) {
- newValue = kMaxIntFracSig;
- }
- // 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();
+ if (fields == nullptr) { return; }
+ if (newValue == fields->properties.maximumFractionDigits) { return; }
+ // cap for backward compatibility, formerly 340, now 999
+ if (newValue > kMaxIntFracSig) {
+ newValue = kMaxIntFracSig;
+ }
+ // 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();
}
void DecimalFormat::setMinimumFractionDigits(int32_t newValue) {
- if (fields == nullptr) { return; }
- 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();
+ if (fields == nullptr) { return; }
+ 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 {
- // Not much we can do to report an error.
- if (fields == nullptr) {
- // Fallback to using the default instance of DecimalFormatProperties.
- return DecimalFormatProperties::getDefault().minimumSignificantDigits;
- }
- return fields->exportedProperties.minimumSignificantDigits;
+ // Not much we can do to report an error.
+ if (fields == nullptr) {
+ // Fallback to using the default instance of DecimalFormatProperties.
+ return DecimalFormatProperties::getDefault().minimumSignificantDigits;
+ }
+ return fields->exportedProperties.minimumSignificantDigits;
}
int32_t DecimalFormat::getMaximumSignificantDigits() const {
- // Not much we can do to report an error.
- if (fields == nullptr) {
- // Fallback to using the default instance of DecimalFormatProperties.
- return DecimalFormatProperties::getDefault().maximumSignificantDigits;
- }
- return fields->exportedProperties.maximumSignificantDigits;
+ // Not much we can do to report an error.
+ if (fields == nullptr) {
+ // Fallback to using the default instance of DecimalFormatProperties.
+ return DecimalFormatProperties::getDefault().maximumSignificantDigits;
+ }
+ return fields->exportedProperties.maximumSignificantDigits;
}
-void DecimalFormat::setMinimumSignificantDigits(int32_t value) {
- if (fields == nullptr) { return; }
- if (value == fields->properties.minimumSignificantDigits) { return; }
- int32_t max = fields->properties.maximumSignificantDigits;
- if (max >= 0 && max < value) {
- fields->properties.maximumSignificantDigits = value;
+void DecimalFormat::setMinimumSignificantDigits(int32_t value) {
+ if (fields == nullptr) { return; }
+ if (value == fields->properties.minimumSignificantDigits) { return; }
+ int32_t max = fields->properties.maximumSignificantDigits;
+ if (max >= 0 && max < value) {
+ fields->properties.maximumSignificantDigits = value;
}
- fields->properties.minimumSignificantDigits = value;
- touchNoError();
+ fields->properties.minimumSignificantDigits = value;
+ touchNoError();
}
-void DecimalFormat::setMaximumSignificantDigits(int32_t value) {
- if (fields == nullptr) { return; }
- if (value == fields->properties.maximumSignificantDigits) { return; }
- int32_t min = fields->properties.minimumSignificantDigits;
- if (min >= 0 && min > value) {
- fields->properties.minimumSignificantDigits = value;
+void DecimalFormat::setMaximumSignificantDigits(int32_t value) {
+ if (fields == nullptr) { return; }
+ if (value == fields->properties.maximumSignificantDigits) { return; }
+ int32_t min = fields->properties.minimumSignificantDigits;
+ if (min >= 0 && min > value) {
+ fields->properties.minimumSignificantDigits = value;
}
- fields->properties.maximumSignificantDigits = value;
- touchNoError();
+ fields->properties.maximumSignificantDigits = value;
+ touchNoError();
}
UBool DecimalFormat::areSignificantDigitsUsed() const {
- const DecimalFormatProperties* dfp;
- // Not much we can do to report an error.
- if (fields == nullptr) {
- // Fallback to using the default instance of DecimalFormatProperties.
- dfp = &(DecimalFormatProperties::getDefault());
- } else {
- dfp = &fields->properties;
- }
- return dfp->minimumSignificantDigits != -1 || dfp->maximumSignificantDigits != -1;
+ const DecimalFormatProperties* dfp;
+ // Not much we can do to report an error.
+ if (fields == nullptr) {
+ // Fallback to using the default instance of DecimalFormatProperties.
+ dfp = &(DecimalFormatProperties::getDefault());
+ } else {
+ dfp = &fields->properties;
+ }
+ return dfp->minimumSignificantDigits != -1 || dfp->maximumSignificantDigits != -1;
}
void DecimalFormat::setSignificantDigitsUsed(UBool useSignificantDigits) {
- if (fields == nullptr) { return; }
-
- // These are the default values from the old implementation.
- if (useSignificantDigits) {
- if (fields->properties.minimumSignificantDigits != -1 ||
- fields->properties.maximumSignificantDigits != -1) {
- return;
- }
- } else {
- if (fields->properties.minimumSignificantDigits == -1 &&
- fields->properties.maximumSignificantDigits == -1) {
- return;
- }
- }
- int32_t minSig = useSignificantDigits ? 1 : -1;
- int32_t maxSig = useSignificantDigits ? 6 : -1;
- fields->properties.minimumSignificantDigits = minSig;
- fields->properties.maximumSignificantDigits = maxSig;
- touchNoError();
-}
-
-void DecimalFormat::setCurrency(const char16_t* theCurrency, UErrorCode& ec) {
- // don't overwrite ec if it's already a failure.
- if (U_FAILURE(ec)) { return; }
- if (fields == nullptr) {
- // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
- ec = U_MEMORY_ALLOCATION_ERROR;
+ if (fields == nullptr) { return; }
+
+ // These are the default values from the old implementation.
+ if (useSignificantDigits) {
+ if (fields->properties.minimumSignificantDigits != -1 ||
+ fields->properties.maximumSignificantDigits != -1) {
+ return;
+ }
+ } else {
+ if (fields->properties.minimumSignificantDigits == -1 &&
+ fields->properties.maximumSignificantDigits == -1) {
+ return;
+ }
+ }
+ int32_t minSig = useSignificantDigits ? 1 : -1;
+ int32_t maxSig = useSignificantDigits ? 6 : -1;
+ fields->properties.minimumSignificantDigits = minSig;
+ fields->properties.maximumSignificantDigits = maxSig;
+ touchNoError();
+}
+
+void DecimalFormat::setCurrency(const char16_t* theCurrency, UErrorCode& ec) {
+ // don't overwrite ec if it's already a failure.
+ if (U_FAILURE(ec)) { return; }
+ if (fields == nullptr) {
+ // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ CurrencyUnit currencyUnit(theCurrency, ec);
+ if (U_FAILURE(ec)) { return; }
+ if (!fields->properties.currency.isNull() && fields->properties.currency.getNoError() == currencyUnit) {
+ return;
+ }
+ NumberFormat::setCurrency(theCurrency, ec); // to set field for compatibility
+ fields->properties.currency = currencyUnit;
+ // In Java, the DecimalFormatSymbols is mutable. Why not in C++?
+ LocalPointer<DecimalFormatSymbols> newSymbols(new DecimalFormatSymbols(*fields->symbols), ec);
+ newSymbols->setCurrency(currencyUnit.getISOCurrency(), ec);
+ fields->symbols.adoptInsteadAndCheckErrorCode(newSymbols.orphan(), ec);
+ touch(ec);
+}
+
+void DecimalFormat::setCurrency(const char16_t* theCurrency) {
+ ErrorCode localStatus;
+ setCurrency(theCurrency, localStatus);
+}
+
+void DecimalFormat::setCurrencyUsage(UCurrencyUsage newUsage, UErrorCode* ec) {
+ // don't overwrite ec if it's already a failure.
+ if (U_FAILURE(*ec)) { return; }
+ if (fields == nullptr) {
+ // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
+ *ec = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ if (!fields->properties.currencyUsage.isNull() && newUsage == fields->properties.currencyUsage.getNoError()) {
+ return;
+ }
+ fields->properties.currencyUsage = newUsage;
+ touch(*ec);
+}
+
+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 == nullptr || fields->properties.currencyUsage.isNull()) {
+ return UCURR_USAGE_STANDARD;
+ }
+ return fields->properties.currencyUsage.getNoError();
+}
+
+void
+DecimalFormat::formatToDecimalQuantity(double number, DecimalQuantity& output, UErrorCode& status) const {
+ // don't overwrite status if it's already a failure.
+ if (U_FAILURE(status)) { return; }
+ if (fields == nullptr) {
+ // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
+ status = U_MEMORY_ALLOCATION_ERROR;
return;
}
- CurrencyUnit currencyUnit(theCurrency, ec);
- if (U_FAILURE(ec)) { return; }
- if (!fields->properties.currency.isNull() && fields->properties.currency.getNoError() == currencyUnit) {
- return;
- }
- NumberFormat::setCurrency(theCurrency, ec); // to set field for compatibility
- fields->properties.currency = currencyUnit;
- // In Java, the DecimalFormatSymbols is mutable. Why not in C++?
- LocalPointer<DecimalFormatSymbols> newSymbols(new DecimalFormatSymbols(*fields->symbols), ec);
- newSymbols->setCurrency(currencyUnit.getISOCurrency(), ec);
- fields->symbols.adoptInsteadAndCheckErrorCode(newSymbols.orphan(), ec);
- touch(ec);
-}
-
-void DecimalFormat::setCurrency(const char16_t* theCurrency) {
- ErrorCode localStatus;
- setCurrency(theCurrency, localStatus);
-}
-
-void DecimalFormat::setCurrencyUsage(UCurrencyUsage newUsage, UErrorCode* ec) {
- // don't overwrite ec if it's already a failure.
- if (U_FAILURE(*ec)) { return; }
- if (fields == nullptr) {
- // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
- *ec = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- if (!fields->properties.currencyUsage.isNull() && newUsage == fields->properties.currencyUsage.getNoError()) {
- return;
- }
- fields->properties.currencyUsage = newUsage;
- touch(*ec);
-}
-
-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 == nullptr || fields->properties.currencyUsage.isNull()) {
- return UCURR_USAGE_STANDARD;
- }
- return fields->properties.currencyUsage.getNoError();
-}
-
-void
-DecimalFormat::formatToDecimalQuantity(double number, DecimalQuantity& output, UErrorCode& status) const {
- // don't overwrite status if it's already a failure.
- if (U_FAILURE(status)) { return; }
- if (fields == nullptr) {
- // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- fields->formatter.formatDouble(number, status).getDecimalQuantity(output, status);
+ fields->formatter.formatDouble(number, status).getDecimalQuantity(output, status);
}
-void DecimalFormat::formatToDecimalQuantity(const Formattable& number, DecimalQuantity& output,
- UErrorCode& status) const {
- // don't overwrite status if it's already a failure.
- if (U_FAILURE(status)) { return; }
- if (fields == nullptr) {
- // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
+void DecimalFormat::formatToDecimalQuantity(const Formattable& number, DecimalQuantity& output,
+ UErrorCode& status) const {
+ // don't overwrite status if it's already a failure.
+ if (U_FAILURE(status)) { return; }
+ if (fields == nullptr) {
+ // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
status = U_MEMORY_ALLOCATION_ERROR;
- return;
+ return;
}
- UFormattedNumberData obj;
- number.populateDecimalQuantity(obj.quantity, status);
- fields->formatter.formatImpl(&obj, status);
- output = std::move(obj.quantity);
+ UFormattedNumberData obj;
+ number.populateDecimalQuantity(obj.quantity, status);
+ fields->formatter.formatImpl(&obj, status);
+ output = std::move(obj.quantity);
}
-const number::LocalizedNumberFormatter* DecimalFormat::toNumberFormatter(UErrorCode& status) const {
- // We sometimes need to return nullptr here (see ICU-20380)
- if (U_FAILURE(status)) { return nullptr; }
- if (fields == nullptr) {
- // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
- status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
+const number::LocalizedNumberFormatter* DecimalFormat::toNumberFormatter(UErrorCode& status) const {
+ // We sometimes need to return nullptr here (see ICU-20380)
+ if (U_FAILURE(status)) { return nullptr; }
+ if (fields == nullptr) {
+ // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
}
- return &fields->formatter;
+ return &fields->formatter;
}
-/** Rebuilds the formatter object from the property bag. */
-void DecimalFormat::touch(UErrorCode& status) {
- if (U_FAILURE(status)) {
+/** Rebuilds the formatter object from the property bag. */
+void DecimalFormat::touch(UErrorCode& status) {
+ if (U_FAILURE(status)) {
return;
}
- if (fields == nullptr) {
- // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
- // For regular construction, the caller should have checked the status variable for errors.
- // For copy construction, there is unfortunately nothing to report the error, so we need to guard against
- // this possible bad state here and set the status to an error.
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
+ if (fields == nullptr) {
+ // We only get here if an OOM error happend during construction, copy construction, assignment, or modification.
+ // For regular construction, the caller should have checked the status variable for errors.
+ // For copy construction, there is unfortunately nothing to report the error, so we need to guard against
+ // this possible bad state here and set the status to an error.
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
}
- // In C++, fields->symbols is the source of truth for the locale.
- Locale locale = fields->symbols->getLocale();
-
- // Note: The formatter is relatively cheap to create, and we need it to populate fields->exportedProperties,
- // so automatically recompute 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?
+ // In C++, fields->symbols is the source of truth for the locale.
+ Locale locale = fields->symbols->getLocale();
+
+ // Note: The formatter is relatively cheap to create, and we need it to populate fields->exportedProperties,
+ // so automatically recompute 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?
+
+ // Since memory has already been allocated for the formatter, we can move assign a stack-allocated object
+ // and don't need to call new. (Which is slower and could possibly fail).
+ fields->formatter = NumberPropertyMapper::create(
+ fields->properties, *fields->symbols, fields->warehouse, fields->exportedProperties, status
+ ).locale(locale);
+
+ // Do this after fields->exportedProperties are set up
+ setupFastFormat();
+
+ // Delete the parsers if they were made previously
+ delete fields->atomicParser.exchange(nullptr);
+ delete fields->atomicCurrencyParser.exchange(nullptr);
+
+ // 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);
+}
+
+void DecimalFormat::touchNoError() {
+ UErrorCode localStatus = U_ZERO_ERROR;
+ touch(localStatus);
+}
+
+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>(ignoreRounding);
+ PatternParser::parseToExistingProperties(pattern, fields->properties, actualIgnoreRounding, status);
+ }
+}
+
+const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& status) const {
+ // TODO: Move this into umutex.h? (similar logic also in numrange_fluent.cpp)
+ // See ICU-20146
+
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+
+ // First try to get the pre-computed parser
+ auto* ptr = fields->atomicParser.load();
+ if (ptr != nullptr) {
+ return ptr;
+ }
+
+ // Try computing the parser on our own
+ auto* temp = NumberParserImpl::createParserFromProperties(fields->properties, *fields->symbols, false, status);
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ if (temp == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+
+ // 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<DecimalFormat*>(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;
+ }
+}
+
+const numparse::impl::NumberParserImpl* DecimalFormat::getCurrencyParser(UErrorCode& status) const {
+ if (U_FAILURE(status)) { return nullptr; }
+
+ // First try to get the pre-computed parser
+ auto* ptr = fields->atomicCurrencyParser.load();
+ if (ptr != nullptr) {
+ return ptr;
+ }
+
+ // 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
+ }
+
+ // 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<DecimalFormat*>(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;
+ }
+}
+
+void
+DecimalFormat::fieldPositionHelper(
+ const UFormattedNumberData& formatted,
+ FieldPosition& fieldPosition,
+ int32_t offset,
+ UErrorCode& status) {
+ if (U_FAILURE(status)) { return; }
+ // 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);
+ }
+}
+
+void
+DecimalFormat::fieldPositionIteratorHelper(
+ const UFormattedNumberData& formatted,
+ FieldPositionIterator* fpi,
+ int32_t offset,
+ UErrorCode& status) {
+ if (U_SUCCESS(status) && (fpi != nullptr)) {
+ FieldPositionIteratorHandler fpih(fpi, status);
+ fpih.setShift(offset);
+ formatted.getAllFieldPositions(fpih, status);
+ }
+}
+
+// To debug fast-format, change void(x) to printf(x)
+#define trace(x) void(x)
+
+void DecimalFormat::setupFastFormat() {
+ // Check the majority of properties:
+ if (!fields->properties.equalsDefaultExceptFastFormat()) {
+ trace("no fast format: equality\n");
+ fields->canUseFastFormat = false;
+ return;
+ }
+
+ // 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;
+ }
+
+ // 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;
+ }
+
+ // 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;
+ }
+
+ // 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;
+ }
+
+ // 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;
+ }
+
+ // Good to go!
+ trace("can use fast format!\n");
+ fields->canUseFastFormat = true;
+ fields->fastData.cpZero = static_cast<char16_t>(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<int8_t>(minInt);
+ fields->fastData.maxInt = (maxInt < 0 || maxInt > 127) ? 127 : static_cast<int8_t>(maxInt);
+}
+
+bool DecimalFormat::fastFormatDouble(double input, UnicodeString& output) const {
+ if (!fields->canUseFastFormat) {
+ return false;
+ }
+ if (std::isnan(input)
+ || uprv_trunc(input) != input
+ || input <= INT32_MIN
+ || input > INT32_MAX) {
+ return false;
+ }
+ doFastFormatInt32(static_cast<int32_t>(input), std::signbit(input), output);
+ return true;
+}
+
+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<int32_t>(input), input < 0, output);
+ return true;
+}
+
+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;
+ int8_t minInt = (fields->fastData.minInt < 1)? 1: fields->fastData.minInt;
+ for (int8_t i = 0; i < fields->fastData.maxInt && (input != 0 || i < 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<char16_t>(fields->fastData.cpZero + res.rem);
+ input = res.quot;
+ }
+ int32_t len = localCapacity - static_cast<int32_t>(ptr - localBuffer);
+ output.append(ptr, len);
+}
+
- // Since memory has already been allocated for the formatter, we can move assign a stack-allocated object
- // and don't need to call new. (Which is slower and could possibly fail).
- fields->formatter = NumberPropertyMapper::create(
- fields->properties, *fields->symbols, fields->warehouse, fields->exportedProperties, status
- ).locale(locale);
-
- // Do this after fields->exportedProperties are set up
- setupFastFormat();
-
- // Delete the parsers if they were made previously
- delete fields->atomicParser.exchange(nullptr);
- delete fields->atomicCurrencyParser.exchange(nullptr);
-
- // 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);
-}
-
-void DecimalFormat::touchNoError() {
- UErrorCode localStatus = U_ZERO_ERROR;
- touch(localStatus);
-}
-
-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>(ignoreRounding);
- PatternParser::parseToExistingProperties(pattern, fields->properties, actualIgnoreRounding, status);
- }
-}
-
-const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& status) const {
- // TODO: Move this into umutex.h? (similar logic also in numrange_fluent.cpp)
- // See ICU-20146
-
- if (U_FAILURE(status)) {
- return nullptr;
- }
-
- // First try to get the pre-computed parser
- auto* ptr = fields->atomicParser.load();
- if (ptr != nullptr) {
- return ptr;
- }
-
- // Try computing the parser on our own
- auto* temp = NumberParserImpl::createParserFromProperties(fields->properties, *fields->symbols, false, status);
- if (U_FAILURE(status)) {
- return nullptr;
- }
- if (temp == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
-
- // 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<DecimalFormat*>(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;
- }
-}
-
-const numparse::impl::NumberParserImpl* DecimalFormat::getCurrencyParser(UErrorCode& status) const {
- if (U_FAILURE(status)) { return nullptr; }
-
- // First try to get the pre-computed parser
- auto* ptr = fields->atomicCurrencyParser.load();
- if (ptr != nullptr) {
- return ptr;
- }
-
- // 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
- }
-
- // 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<DecimalFormat*>(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;
- }
-}
-
-void
-DecimalFormat::fieldPositionHelper(
- const UFormattedNumberData& formatted,
- FieldPosition& fieldPosition,
- int32_t offset,
- UErrorCode& status) {
- if (U_FAILURE(status)) { return; }
- // 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);
- }
-}
-
-void
-DecimalFormat::fieldPositionIteratorHelper(
- const UFormattedNumberData& formatted,
- FieldPositionIterator* fpi,
- int32_t offset,
- UErrorCode& status) {
- if (U_SUCCESS(status) && (fpi != nullptr)) {
- FieldPositionIteratorHandler fpih(fpi, status);
- fpih.setShift(offset);
- formatted.getAllFieldPositions(fpih, status);
- }
-}
-
-// To debug fast-format, change void(x) to printf(x)
-#define trace(x) void(x)
-
-void DecimalFormat::setupFastFormat() {
- // Check the majority of properties:
- if (!fields->properties.equalsDefaultExceptFastFormat()) {
- trace("no fast format: equality\n");
- fields->canUseFastFormat = false;
- return;
- }
-
- // 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;
- }
-
- // 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;
- }
-
- // 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;
- }
-
- // 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;
- }
-
- // 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;
- }
-
- // Good to go!
- trace("can use fast format!\n");
- fields->canUseFastFormat = true;
- fields->fastData.cpZero = static_cast<char16_t>(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<int8_t>(minInt);
- fields->fastData.maxInt = (maxInt < 0 || maxInt > 127) ? 127 : static_cast<int8_t>(maxInt);
-}
-
-bool DecimalFormat::fastFormatDouble(double input, UnicodeString& output) const {
- if (!fields->canUseFastFormat) {
- return false;
- }
- if (std::isnan(input)
- || uprv_trunc(input) != input
- || input <= INT32_MIN
- || input > INT32_MAX) {
- return false;
- }
- doFastFormatInt32(static_cast<int32_t>(input), std::signbit(input), output);
- return true;
-}
-
-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<int32_t>(input), input < 0, output);
- return true;
-}
-
-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;
- int8_t minInt = (fields->fastData.minInt < 1)? 1: fields->fastData.minInt;
- for (int8_t i = 0; i < fields->fastData.maxInt && (input != 0 || i < 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<char16_t>(fields->fastData.cpZero + res.rem);
- input = res.quot;
- }
- int32_t len = localCapacity - static_cast<int32_t>(ptr - localBuffer);
- output.append(ptr, len);
-}
-
-
#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/double-conversion-bignum-dtoa.cpp b/contrib/libs/icu/i18n/double-conversion-bignum-dtoa.cpp
index a95910df04..bc7e408f68 100644
--- a/contrib/libs/icu/i18n/double-conversion-bignum-dtoa.cpp
+++ b/contrib/libs/icu/i18n/double-conversion-bignum-dtoa.cpp
@@ -1,659 +1,659 @@
-// © 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 <cmath>
-
-// ICU PATCH: Customize header file paths for ICU.
-
-#include "double-conversion-bignum-dtoa.h"
-
-#include "double-conversion-bignum.h"
-#include "double-conversion-ieee.h"
-
-// ICU PATCH: Wrap in ICU namespace
-U_NAMESPACE_BEGIN
-
-namespace double_conversion {
-
-static int NormalizedExponent(uint64_t significand, int exponent) {
- DOUBLE_CONVERSION_ASSERT(significand != 0);
- while ((significand & Double::kHiddenBit) == 0) {
- significand = significand << 1;
- exponent = exponent - 1;
- }
- return exponent;
-}
-
-
-// Forward declarations:
-// Returns an estimation of k such that 10^(k-1) <= v < 10^k.
-static int EstimatePower(int exponent);
-// Computes v / 10^estimated_power exactly, as a ratio of two bignums, numerator
-// and denominator.
-static void InitialScaledStartValues(uint64_t significand,
- int exponent,
- bool lower_boundary_is_closer,
- int estimated_power,
- bool need_boundary_deltas,
- Bignum* numerator,
- Bignum* denominator,
- Bignum* delta_minus,
- Bignum* delta_plus);
-// Multiplies numerator/denominator so that its values lies in the range 1-10.
-// Returns decimal_point s.t.
-// v = numerator'/denominator' * 10^(decimal_point-1)
-// where numerator' and denominator' are the values of numerator and
-// denominator after the call to this function.
-static void FixupMultiply10(int estimated_power, bool is_even,
- int* decimal_point,
- Bignum* numerator, Bignum* denominator,
- Bignum* delta_minus, Bignum* delta_plus);
-// Generates digits from the left to the right and stops when the generated
-// digits yield the shortest decimal representation of v.
-static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator,
- Bignum* delta_minus, Bignum* delta_plus,
- bool is_even,
- Vector<char> buffer, int* length);
-// Generates 'requested_digits' after the decimal point.
-static void BignumToFixed(int requested_digits, int* decimal_point,
- Bignum* numerator, Bignum* denominator,
- Vector<char> buffer, int* length);
-// Generates 'count' digits of numerator/denominator.
-// Once 'count' digits have been produced rounds the result depending on the
-// remainder (remainders of exactly .5 round upwards). Might update the
-// decimal_point when rounding up (for example for 0.9999).
-static void GenerateCountedDigits(int count, int* decimal_point,
- Bignum* numerator, Bignum* denominator,
- Vector<char> buffer, int* length);
-
-
-void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits,
- Vector<char> buffer, int* length, int* decimal_point) {
- DOUBLE_CONVERSION_ASSERT(v > 0);
- DOUBLE_CONVERSION_ASSERT(!Double(v).IsSpecial());
- uint64_t significand;
- int exponent;
- bool lower_boundary_is_closer;
- if (mode == BIGNUM_DTOA_SHORTEST_SINGLE) {
- float f = static_cast<float>(v);
- DOUBLE_CONVERSION_ASSERT(f == v);
- significand = Single(f).Significand();
- exponent = Single(f).Exponent();
- lower_boundary_is_closer = Single(f).LowerBoundaryIsCloser();
- } else {
- significand = Double(v).Significand();
- exponent = Double(v).Exponent();
- lower_boundary_is_closer = Double(v).LowerBoundaryIsCloser();
- }
- bool need_boundary_deltas =
- (mode == BIGNUM_DTOA_SHORTEST || mode == BIGNUM_DTOA_SHORTEST_SINGLE);
-
- bool is_even = (significand & 1) == 0;
- int normalized_exponent = NormalizedExponent(significand, exponent);
- // estimated_power might be too low by 1.
- int estimated_power = EstimatePower(normalized_exponent);
-
- // Shortcut for Fixed.
- // The requested digits correspond to the digits after the point. If the
- // number is much too small, then there is no need in trying to get any
- // digits.
- if (mode == BIGNUM_DTOA_FIXED && -estimated_power - 1 > requested_digits) {
- buffer[0] = '\0';
- *length = 0;
- // Set decimal-point to -requested_digits. This is what Gay does.
- // Note that it should not have any effect anyways since the string is
- // empty.
- *decimal_point = -requested_digits;
- return;
- }
-
- Bignum numerator;
- Bignum denominator;
- Bignum delta_minus;
- Bignum delta_plus;
- // Make sure the bignum can grow large enough. The smallest double equals
- // 4e-324. In this case the denominator needs fewer than 324*4 binary digits.
- // The maximum double is 1.7976931348623157e308 which needs fewer than
- // 308*4 binary digits.
- DOUBLE_CONVERSION_ASSERT(Bignum::kMaxSignificantBits >= 324*4);
- InitialScaledStartValues(significand, exponent, lower_boundary_is_closer,
- estimated_power, need_boundary_deltas,
- &numerator, &denominator,
- &delta_minus, &delta_plus);
- // We now have v = (numerator / denominator) * 10^estimated_power.
- FixupMultiply10(estimated_power, is_even, decimal_point,
- &numerator, &denominator,
- &delta_minus, &delta_plus);
- // We now have v = (numerator / denominator) * 10^(decimal_point-1), and
- // 1 <= (numerator + delta_plus) / denominator < 10
- switch (mode) {
- case BIGNUM_DTOA_SHORTEST:
- case BIGNUM_DTOA_SHORTEST_SINGLE:
- GenerateShortestDigits(&numerator, &denominator,
- &delta_minus, &delta_plus,
- is_even, buffer, length);
- break;
- case BIGNUM_DTOA_FIXED:
- BignumToFixed(requested_digits, decimal_point,
- &numerator, &denominator,
- buffer, length);
- break;
- case BIGNUM_DTOA_PRECISION:
- GenerateCountedDigits(requested_digits, decimal_point,
- &numerator, &denominator,
- buffer, length);
- break;
- default:
- DOUBLE_CONVERSION_UNREACHABLE();
- }
- buffer[*length] = '\0';
-}
-
-
-// The procedure starts generating digits from the left to the right and stops
-// when the generated digits yield the shortest decimal representation of v. A
-// decimal representation of v is a number lying closer to v than to any other
-// double, so it converts to v when read.
-//
-// This is true if d, the decimal representation, is between m- and m+, the
-// upper and lower boundaries. d must be strictly between them if !is_even.
-// m- := (numerator - delta_minus) / denominator
-// m+ := (numerator + delta_plus) / denominator
-//
-// Precondition: 0 <= (numerator+delta_plus) / denominator < 10.
-// If 1 <= (numerator+delta_plus) / denominator < 10 then no leading 0 digit
-// will be produced. This should be the standard precondition.
-static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator,
- Bignum* delta_minus, Bignum* delta_plus,
- bool is_even,
- Vector<char> buffer, int* length) {
- // Small optimization: if delta_minus and delta_plus are the same just reuse
- // one of the two bignums.
- if (Bignum::Equal(*delta_minus, *delta_plus)) {
- delta_plus = delta_minus;
- }
- *length = 0;
- for (;;) {
- uint16_t digit;
- digit = numerator->DivideModuloIntBignum(*denominator);
- DOUBLE_CONVERSION_ASSERT(digit <= 9); // digit is a uint16_t and therefore always positive.
- // digit = numerator / denominator (integer division).
- // numerator = numerator % denominator.
- buffer[(*length)++] = static_cast<char>(digit + '0');
-
- // Can we stop already?
- // If the remainder of the division is less than the distance to the lower
- // boundary we can stop. In this case we simply round down (discarding the
- // remainder).
- // Similarly we test if we can round up (using the upper boundary).
- bool in_delta_room_minus;
- bool in_delta_room_plus;
- if (is_even) {
- in_delta_room_minus = Bignum::LessEqual(*numerator, *delta_minus);
- } else {
- in_delta_room_minus = Bignum::Less(*numerator, *delta_minus);
- }
- if (is_even) {
- in_delta_room_plus =
- Bignum::PlusCompare(*numerator, *delta_plus, *denominator) >= 0;
- } else {
- in_delta_room_plus =
- Bignum::PlusCompare(*numerator, *delta_plus, *denominator) > 0;
- }
- if (!in_delta_room_minus && !in_delta_room_plus) {
- // Prepare for next iteration.
- numerator->Times10();
- delta_minus->Times10();
- // We optimized delta_plus to be equal to delta_minus (if they share the
- // same value). So don't multiply delta_plus if they point to the same
- // object.
- if (delta_minus != delta_plus) {
- delta_plus->Times10();
- }
- } else if (in_delta_room_minus && in_delta_room_plus) {
- // Let's see if 2*numerator < denominator.
- // If yes, then the next digit would be < 5 and we can round down.
- int compare = Bignum::PlusCompare(*numerator, *numerator, *denominator);
- if (compare < 0) {
- // Remaining digits are less than .5. -> Round down (== do nothing).
- } else if (compare > 0) {
- // Remaining digits are more than .5 of denominator. -> Round up.
- // Note that the last digit could not be a '9' as otherwise the whole
- // loop would have stopped earlier.
- // We still have an assert here in case the preconditions were not
- // satisfied.
- DOUBLE_CONVERSION_ASSERT(buffer[(*length) - 1] != '9');
- buffer[(*length) - 1]++;
- } else {
- // Halfway case.
- // TODO(floitsch): need a way to solve half-way cases.
- // For now let's round towards even (since this is what Gay seems to
- // do).
-
- if ((buffer[(*length) - 1] - '0') % 2 == 0) {
- // Round down => Do nothing.
- } else {
- DOUBLE_CONVERSION_ASSERT(buffer[(*length) - 1] != '9');
- buffer[(*length) - 1]++;
- }
- }
- return;
- } else if (in_delta_room_minus) {
- // Round down (== do nothing).
- return;
- } else { // in_delta_room_plus
- // Round up.
- // Note again that the last digit could not be '9' since this would have
- // stopped the loop earlier.
- // We still have an DOUBLE_CONVERSION_ASSERT here, in case the preconditions were not
- // satisfied.
- DOUBLE_CONVERSION_ASSERT(buffer[(*length) -1] != '9');
- buffer[(*length) - 1]++;
- return;
- }
- }
-}
-
-
-// Let v = numerator / denominator < 10.
-// Then we generate 'count' digits of d = x.xxxxx... (without the decimal point)
-// from left to right. Once 'count' digits have been produced we decide wether
-// to round up or down. Remainders of exactly .5 round upwards. Numbers such
-// as 9.999999 propagate a carry all the way, and change the
-// exponent (decimal_point), when rounding upwards.
-static void GenerateCountedDigits(int count, int* decimal_point,
- Bignum* numerator, Bignum* denominator,
- Vector<char> buffer, int* length) {
- DOUBLE_CONVERSION_ASSERT(count >= 0);
- for (int i = 0; i < count - 1; ++i) {
- uint16_t digit;
- digit = numerator->DivideModuloIntBignum(*denominator);
- DOUBLE_CONVERSION_ASSERT(digit <= 9); // digit is a uint16_t and therefore always positive.
- // digit = numerator / denominator (integer division).
- // numerator = numerator % denominator.
- buffer[i] = static_cast<char>(digit + '0');
- // Prepare for next iteration.
- numerator->Times10();
- }
- // Generate the last digit.
- uint16_t digit;
- digit = numerator->DivideModuloIntBignum(*denominator);
- if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) {
- digit++;
- }
- DOUBLE_CONVERSION_ASSERT(digit <= 10);
- buffer[count - 1] = static_cast<char>(digit + '0');
- // Correct bad digits (in case we had a sequence of '9's). Propagate the
- // carry until we hat a non-'9' or til we reach the first digit.
- for (int i = count - 1; i > 0; --i) {
- if (buffer[i] != '0' + 10) break;
- buffer[i] = '0';
- buffer[i - 1]++;
- }
- if (buffer[0] == '0' + 10) {
- // Propagate a carry past the top place.
- buffer[0] = '1';
- (*decimal_point)++;
- }
- *length = count;
-}
-
-
-// Generates 'requested_digits' after the decimal point. It might omit
-// trailing '0's. If the input number is too small then no digits at all are
-// generated (ex.: 2 fixed digits for 0.00001).
-//
-// Input verifies: 1 <= (numerator + delta) / denominator < 10.
-static void BignumToFixed(int requested_digits, int* decimal_point,
- Bignum* numerator, Bignum* denominator,
- Vector<char> buffer, int* length) {
- // Note that we have to look at more than just the requested_digits, since
- // a number could be rounded up. Example: v=0.5 with requested_digits=0.
- // Even though the power of v equals 0 we can't just stop here.
- if (-(*decimal_point) > requested_digits) {
- // The number is definitively too small.
- // Ex: 0.001 with requested_digits == 1.
- // Set decimal-point to -requested_digits. This is what Gay does.
- // Note that it should not have any effect anyways since the string is
- // empty.
- *decimal_point = -requested_digits;
- *length = 0;
- return;
- } else if (-(*decimal_point) == requested_digits) {
- // We only need to verify if the number rounds down or up.
- // Ex: 0.04 and 0.06 with requested_digits == 1.
- DOUBLE_CONVERSION_ASSERT(*decimal_point == -requested_digits);
- // Initially the fraction lies in range (1, 10]. Multiply the denominator
- // by 10 so that we can compare more easily.
- denominator->Times10();
- if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) {
- // If the fraction is >= 0.5 then we have to include the rounded
- // digit.
- buffer[0] = '1';
- *length = 1;
- (*decimal_point)++;
- } else {
- // Note that we caught most of similar cases earlier.
- *length = 0;
- }
- return;
- } else {
- // The requested digits correspond to the digits after the point.
- // The variable 'needed_digits' includes the digits before the point.
- int needed_digits = (*decimal_point) + requested_digits;
- GenerateCountedDigits(needed_digits, decimal_point,
- numerator, denominator,
- buffer, length);
- }
-}
-
-
-// Returns an estimation of k such that 10^(k-1) <= v < 10^k where
-// v = f * 2^exponent and 2^52 <= f < 2^53.
-// v is hence a normalized double with the given exponent. The output is an
-// approximation for the exponent of the decimal approimation .digits * 10^k.
-//
-// The result might undershoot by 1 in which case 10^k <= v < 10^k+1.
-// Note: this property holds for v's upper boundary m+ too.
-// 10^k <= m+ < 10^k+1.
-// (see explanation below).
-//
-// Examples:
-// EstimatePower(0) => 16
-// EstimatePower(-52) => 0
-//
-// Note: e >= 0 => EstimatedPower(e) > 0. No similar claim can be made for e<0.
-static int EstimatePower(int exponent) {
- // This function estimates log10 of v where v = f*2^e (with e == exponent).
- // Note that 10^floor(log10(v)) <= v, but v <= 10^ceil(log10(v)).
- // Note that f is bounded by its container size. Let p = 53 (the double's
- // significand size). Then 2^(p-1) <= f < 2^p.
- //
- // Given that log10(v) == log2(v)/log2(10) and e+(len(f)-1) is quite close
- // to log2(v) the function is simplified to (e+(len(f)-1)/log2(10)).
- // The computed number undershoots by less than 0.631 (when we compute log3
- // and not log10).
- //
- // Optimization: since we only need an approximated result this computation
- // can be performed on 64 bit integers. On x86/x64 architecture the speedup is
- // not really measurable, though.
- //
- // Since we want to avoid overshooting we decrement by 1e10 so that
- // floating-point imprecisions don't affect us.
- //
- // Explanation for v's boundary m+: the computation takes advantage of
- // the fact that 2^(p-1) <= f < 2^p. Boundaries still satisfy this requirement
- // (even for denormals where the delta can be much more important).
-
- const double k1Log10 = 0.30102999566398114; // 1/lg(10)
-
- // For doubles len(f) == 53 (don't forget the hidden bit).
- const int kSignificandSize = Double::kSignificandSize;
- double estimate = ceil((exponent + kSignificandSize - 1) * k1Log10 - 1e-10);
- return static_cast<int>(estimate);
-}
-
-
-// See comments for InitialScaledStartValues.
-static void InitialScaledStartValuesPositiveExponent(
- uint64_t significand, int exponent,
- int estimated_power, bool need_boundary_deltas,
- Bignum* numerator, Bignum* denominator,
- Bignum* delta_minus, Bignum* delta_plus) {
- // A positive exponent implies a positive power.
- DOUBLE_CONVERSION_ASSERT(estimated_power >= 0);
- // Since the estimated_power is positive we simply multiply the denominator
- // by 10^estimated_power.
-
- // numerator = v.
- numerator->AssignUInt64(significand);
- numerator->ShiftLeft(exponent);
- // denominator = 10^estimated_power.
- denominator->AssignPowerUInt16(10, estimated_power);
-
- if (need_boundary_deltas) {
- // Introduce a common denominator so that the deltas to the boundaries are
- // integers.
- denominator->ShiftLeft(1);
- numerator->ShiftLeft(1);
- // Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common
- // denominator (of 2) delta_plus equals 2^e.
- delta_plus->AssignUInt16(1);
- delta_plus->ShiftLeft(exponent);
- // Same for delta_minus. The adjustments if f == 2^p-1 are done later.
- delta_minus->AssignUInt16(1);
- delta_minus->ShiftLeft(exponent);
- }
-}
-
-
-// See comments for InitialScaledStartValues
-static void InitialScaledStartValuesNegativeExponentPositivePower(
- uint64_t significand, int exponent,
- int estimated_power, bool need_boundary_deltas,
- Bignum* numerator, Bignum* denominator,
- Bignum* delta_minus, Bignum* delta_plus) {
- // v = f * 2^e with e < 0, and with estimated_power >= 0.
- // This means that e is close to 0 (have a look at how estimated_power is
- // computed).
-
- // numerator = significand
- // since v = significand * 2^exponent this is equivalent to
- // numerator = v * / 2^-exponent
- numerator->AssignUInt64(significand);
- // denominator = 10^estimated_power * 2^-exponent (with exponent < 0)
- denominator->AssignPowerUInt16(10, estimated_power);
- denominator->ShiftLeft(-exponent);
-
- if (need_boundary_deltas) {
- // Introduce a common denominator so that the deltas to the boundaries are
- // integers.
- denominator->ShiftLeft(1);
- numerator->ShiftLeft(1);
- // Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common
- // denominator (of 2) delta_plus equals 2^e.
- // Given that the denominator already includes v's exponent the distance
- // to the boundaries is simply 1.
- delta_plus->AssignUInt16(1);
- // Same for delta_minus. The adjustments if f == 2^p-1 are done later.
- delta_minus->AssignUInt16(1);
- }
-}
-
-
-// See comments for InitialScaledStartValues
-static void InitialScaledStartValuesNegativeExponentNegativePower(
- uint64_t significand, int exponent,
- int estimated_power, bool need_boundary_deltas,
- Bignum* numerator, Bignum* denominator,
- Bignum* delta_minus, Bignum* delta_plus) {
- // Instead of multiplying the denominator with 10^estimated_power we
- // multiply all values (numerator and deltas) by 10^-estimated_power.
-
- // Use numerator as temporary container for power_ten.
- Bignum* power_ten = numerator;
- power_ten->AssignPowerUInt16(10, -estimated_power);
-
- if (need_boundary_deltas) {
- // Since power_ten == numerator we must make a copy of 10^estimated_power
- // before we complete the computation of the numerator.
- // delta_plus = delta_minus = 10^estimated_power
- delta_plus->AssignBignum(*power_ten);
- delta_minus->AssignBignum(*power_ten);
- }
-
- // numerator = significand * 2 * 10^-estimated_power
- // since v = significand * 2^exponent this is equivalent to
- // numerator = v * 10^-estimated_power * 2 * 2^-exponent.
- // Remember: numerator has been abused as power_ten. So no need to assign it
- // to itself.
- DOUBLE_CONVERSION_ASSERT(numerator == power_ten);
- numerator->MultiplyByUInt64(significand);
-
- // denominator = 2 * 2^-exponent with exponent < 0.
- denominator->AssignUInt16(1);
- denominator->ShiftLeft(-exponent);
-
- if (need_boundary_deltas) {
- // Introduce a common denominator so that the deltas to the boundaries are
- // integers.
- numerator->ShiftLeft(1);
- denominator->ShiftLeft(1);
- // With this shift the boundaries have their correct value, since
- // delta_plus = 10^-estimated_power, and
- // delta_minus = 10^-estimated_power.
- // These assignments have been done earlier.
- // The adjustments if f == 2^p-1 (lower boundary is closer) are done later.
- }
-}
-
-
-// Let v = significand * 2^exponent.
-// Computes v / 10^estimated_power exactly, as a ratio of two bignums, numerator
-// and denominator. The functions GenerateShortestDigits and
-// GenerateCountedDigits will then convert this ratio to its decimal
-// representation d, with the required accuracy.
-// Then d * 10^estimated_power is the representation of v.
-// (Note: the fraction and the estimated_power might get adjusted before
-// generating the decimal representation.)
-//
-// The initial start values consist of:
-// - a scaled numerator: s.t. numerator/denominator == v / 10^estimated_power.
-// - a scaled (common) denominator.
-// optionally (used by GenerateShortestDigits to decide if it has the shortest
-// decimal converting back to v):
-// - v - m-: the distance to the lower boundary.
-// - m+ - v: the distance to the upper boundary.
-//
-// v, m+, m-, and therefore v - m- and m+ - v all share the same denominator.
-//
-// Let ep == estimated_power, then the returned values will satisfy:
-// v / 10^ep = numerator / denominator.
-// v's boundarys m- and m+:
-// m- / 10^ep == v / 10^ep - delta_minus / denominator
-// m+ / 10^ep == v / 10^ep + delta_plus / denominator
-// Or in other words:
-// m- == v - delta_minus * 10^ep / denominator;
-// m+ == v + delta_plus * 10^ep / denominator;
-//
-// Since 10^(k-1) <= v < 10^k (with k == estimated_power)
-// or 10^k <= v < 10^(k+1)
-// we then have 0.1 <= numerator/denominator < 1
-// or 1 <= numerator/denominator < 10
-//
-// It is then easy to kickstart the digit-generation routine.
-//
-// The boundary-deltas are only filled if the mode equals BIGNUM_DTOA_SHORTEST
-// or BIGNUM_DTOA_SHORTEST_SINGLE.
-
-static void InitialScaledStartValues(uint64_t significand,
- int exponent,
- bool lower_boundary_is_closer,
- int estimated_power,
- bool need_boundary_deltas,
- Bignum* numerator,
- Bignum* denominator,
- Bignum* delta_minus,
- Bignum* delta_plus) {
- if (exponent >= 0) {
- InitialScaledStartValuesPositiveExponent(
- significand, exponent, estimated_power, need_boundary_deltas,
- numerator, denominator, delta_minus, delta_plus);
- } else if (estimated_power >= 0) {
- InitialScaledStartValuesNegativeExponentPositivePower(
- significand, exponent, estimated_power, need_boundary_deltas,
- numerator, denominator, delta_minus, delta_plus);
- } else {
- InitialScaledStartValuesNegativeExponentNegativePower(
- significand, exponent, estimated_power, need_boundary_deltas,
- numerator, denominator, delta_minus, delta_plus);
- }
-
- if (need_boundary_deltas && lower_boundary_is_closer) {
- // The lower boundary is closer at half the distance of "normal" numbers.
- // Increase the common denominator and adapt all but the delta_minus.
- denominator->ShiftLeft(1); // *2
- numerator->ShiftLeft(1); // *2
- delta_plus->ShiftLeft(1); // *2
- }
-}
-
-
-// This routine multiplies numerator/denominator so that its values lies in the
-// range 1-10. That is after a call to this function we have:
-// 1 <= (numerator + delta_plus) /denominator < 10.
-// Let numerator the input before modification and numerator' the argument
-// after modification, then the output-parameter decimal_point is such that
-// numerator / denominator * 10^estimated_power ==
-// numerator' / denominator' * 10^(decimal_point - 1)
-// In some cases estimated_power was too low, and this is already the case. We
-// then simply adjust the power so that 10^(k-1) <= v < 10^k (with k ==
-// estimated_power) but do not touch the numerator or denominator.
-// Otherwise the routine multiplies the numerator and the deltas by 10.
-static void FixupMultiply10(int estimated_power, bool is_even,
- int* decimal_point,
- Bignum* numerator, Bignum* denominator,
- Bignum* delta_minus, Bignum* delta_plus) {
- bool in_range;
- if (is_even) {
- // For IEEE doubles half-way cases (in decimal system numbers ending with 5)
- // are rounded to the closest floating-point number with even significand.
- in_range = Bignum::PlusCompare(*numerator, *delta_plus, *denominator) >= 0;
- } else {
- in_range = Bignum::PlusCompare(*numerator, *delta_plus, *denominator) > 0;
- }
- if (in_range) {
- // Since numerator + delta_plus >= denominator we already have
- // 1 <= numerator/denominator < 10. Simply update the estimated_power.
- *decimal_point = estimated_power + 1;
- } else {
- *decimal_point = estimated_power;
- numerator->Times10();
- if (Bignum::Equal(*delta_minus, *delta_plus)) {
- delta_minus->Times10();
- delta_plus->AssignBignum(*delta_minus);
- } else {
- delta_minus->Times10();
- delta_plus->Times10();
- }
- }
-}
-
-} // namespace double_conversion
-
-// ICU PATCH: Close ICU namespace
-U_NAMESPACE_END
-#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
+// © 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 <cmath>
+
+// ICU PATCH: Customize header file paths for ICU.
+
+#include "double-conversion-bignum-dtoa.h"
+
+#include "double-conversion-bignum.h"
+#include "double-conversion-ieee.h"
+
+// ICU PATCH: Wrap in ICU namespace
+U_NAMESPACE_BEGIN
+
+namespace double_conversion {
+
+static int NormalizedExponent(uint64_t significand, int exponent) {
+ DOUBLE_CONVERSION_ASSERT(significand != 0);
+ while ((significand & Double::kHiddenBit) == 0) {
+ significand = significand << 1;
+ exponent = exponent - 1;
+ }
+ return exponent;
+}
+
+
+// Forward declarations:
+// Returns an estimation of k such that 10^(k-1) <= v < 10^k.
+static int EstimatePower(int exponent);
+// Computes v / 10^estimated_power exactly, as a ratio of two bignums, numerator
+// and denominator.
+static void InitialScaledStartValues(uint64_t significand,
+ int exponent,
+ bool lower_boundary_is_closer,
+ int estimated_power,
+ bool need_boundary_deltas,
+ Bignum* numerator,
+ Bignum* denominator,
+ Bignum* delta_minus,
+ Bignum* delta_plus);
+// Multiplies numerator/denominator so that its values lies in the range 1-10.
+// Returns decimal_point s.t.
+// v = numerator'/denominator' * 10^(decimal_point-1)
+// where numerator' and denominator' are the values of numerator and
+// denominator after the call to this function.
+static void FixupMultiply10(int estimated_power, bool is_even,
+ int* decimal_point,
+ Bignum* numerator, Bignum* denominator,
+ Bignum* delta_minus, Bignum* delta_plus);
+// Generates digits from the left to the right and stops when the generated
+// digits yield the shortest decimal representation of v.
+static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator,
+ Bignum* delta_minus, Bignum* delta_plus,
+ bool is_even,
+ Vector<char> buffer, int* length);
+// Generates 'requested_digits' after the decimal point.
+static void BignumToFixed(int requested_digits, int* decimal_point,
+ Bignum* numerator, Bignum* denominator,
+ Vector<char> buffer, int* length);
+// Generates 'count' digits of numerator/denominator.
+// Once 'count' digits have been produced rounds the result depending on the
+// remainder (remainders of exactly .5 round upwards). Might update the
+// decimal_point when rounding up (for example for 0.9999).
+static void GenerateCountedDigits(int count, int* decimal_point,
+ Bignum* numerator, Bignum* denominator,
+ Vector<char> buffer, int* length);
+
+
+void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits,
+ Vector<char> buffer, int* length, int* decimal_point) {
+ DOUBLE_CONVERSION_ASSERT(v > 0);
+ DOUBLE_CONVERSION_ASSERT(!Double(v).IsSpecial());
+ uint64_t significand;
+ int exponent;
+ bool lower_boundary_is_closer;
+ if (mode == BIGNUM_DTOA_SHORTEST_SINGLE) {
+ float f = static_cast<float>(v);
+ DOUBLE_CONVERSION_ASSERT(f == v);
+ significand = Single(f).Significand();
+ exponent = Single(f).Exponent();
+ lower_boundary_is_closer = Single(f).LowerBoundaryIsCloser();
+ } else {
+ significand = Double(v).Significand();
+ exponent = Double(v).Exponent();
+ lower_boundary_is_closer = Double(v).LowerBoundaryIsCloser();
+ }
+ bool need_boundary_deltas =
+ (mode == BIGNUM_DTOA_SHORTEST || mode == BIGNUM_DTOA_SHORTEST_SINGLE);
+
+ bool is_even = (significand & 1) == 0;
+ int normalized_exponent = NormalizedExponent(significand, exponent);
+ // estimated_power might be too low by 1.
+ int estimated_power = EstimatePower(normalized_exponent);
+
+ // Shortcut for Fixed.
+ // The requested digits correspond to the digits after the point. If the
+ // number is much too small, then there is no need in trying to get any
+ // digits.
+ if (mode == BIGNUM_DTOA_FIXED && -estimated_power - 1 > requested_digits) {
+ buffer[0] = '\0';
+ *length = 0;
+ // Set decimal-point to -requested_digits. This is what Gay does.
+ // Note that it should not have any effect anyways since the string is
+ // empty.
+ *decimal_point = -requested_digits;
+ return;
+ }
+
+ Bignum numerator;
+ Bignum denominator;
+ Bignum delta_minus;
+ Bignum delta_plus;
+ // Make sure the bignum can grow large enough. The smallest double equals
+ // 4e-324. In this case the denominator needs fewer than 324*4 binary digits.
+ // The maximum double is 1.7976931348623157e308 which needs fewer than
+ // 308*4 binary digits.
+ DOUBLE_CONVERSION_ASSERT(Bignum::kMaxSignificantBits >= 324*4);
+ InitialScaledStartValues(significand, exponent, lower_boundary_is_closer,
+ estimated_power, need_boundary_deltas,
+ &numerator, &denominator,
+ &delta_minus, &delta_plus);
+ // We now have v = (numerator / denominator) * 10^estimated_power.
+ FixupMultiply10(estimated_power, is_even, decimal_point,
+ &numerator, &denominator,
+ &delta_minus, &delta_plus);
+ // We now have v = (numerator / denominator) * 10^(decimal_point-1), and
+ // 1 <= (numerator + delta_plus) / denominator < 10
+ switch (mode) {
+ case BIGNUM_DTOA_SHORTEST:
+ case BIGNUM_DTOA_SHORTEST_SINGLE:
+ GenerateShortestDigits(&numerator, &denominator,
+ &delta_minus, &delta_plus,
+ is_even, buffer, length);
+ break;
+ case BIGNUM_DTOA_FIXED:
+ BignumToFixed(requested_digits, decimal_point,
+ &numerator, &denominator,
+ buffer, length);
+ break;
+ case BIGNUM_DTOA_PRECISION:
+ GenerateCountedDigits(requested_digits, decimal_point,
+ &numerator, &denominator,
+ buffer, length);
+ break;
+ default:
+ DOUBLE_CONVERSION_UNREACHABLE();
+ }
+ buffer[*length] = '\0';
+}
+
+
+// The procedure starts generating digits from the left to the right and stops
+// when the generated digits yield the shortest decimal representation of v. A
+// decimal representation of v is a number lying closer to v than to any other
+// double, so it converts to v when read.
+//
+// This is true if d, the decimal representation, is between m- and m+, the
+// upper and lower boundaries. d must be strictly between them if !is_even.
+// m- := (numerator - delta_minus) / denominator
+// m+ := (numerator + delta_plus) / denominator
+//
+// Precondition: 0 <= (numerator+delta_plus) / denominator < 10.
+// If 1 <= (numerator+delta_plus) / denominator < 10 then no leading 0 digit
+// will be produced. This should be the standard precondition.
+static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator,
+ Bignum* delta_minus, Bignum* delta_plus,
+ bool is_even,
+ Vector<char> buffer, int* length) {
+ // Small optimization: if delta_minus and delta_plus are the same just reuse
+ // one of the two bignums.
+ if (Bignum::Equal(*delta_minus, *delta_plus)) {
+ delta_plus = delta_minus;
+ }
+ *length = 0;
+ for (;;) {
+ uint16_t digit;
+ digit = numerator->DivideModuloIntBignum(*denominator);
+ DOUBLE_CONVERSION_ASSERT(digit <= 9); // digit is a uint16_t and therefore always positive.
+ // digit = numerator / denominator (integer division).
+ // numerator = numerator % denominator.
+ buffer[(*length)++] = static_cast<char>(digit + '0');
+
+ // Can we stop already?
+ // If the remainder of the division is less than the distance to the lower
+ // boundary we can stop. In this case we simply round down (discarding the
+ // remainder).
+ // Similarly we test if we can round up (using the upper boundary).
+ bool in_delta_room_minus;
+ bool in_delta_room_plus;
+ if (is_even) {
+ in_delta_room_minus = Bignum::LessEqual(*numerator, *delta_minus);
+ } else {
+ in_delta_room_minus = Bignum::Less(*numerator, *delta_minus);
+ }
+ if (is_even) {
+ in_delta_room_plus =
+ Bignum::PlusCompare(*numerator, *delta_plus, *denominator) >= 0;
+ } else {
+ in_delta_room_plus =
+ Bignum::PlusCompare(*numerator, *delta_plus, *denominator) > 0;
+ }
+ if (!in_delta_room_minus && !in_delta_room_plus) {
+ // Prepare for next iteration.
+ numerator->Times10();
+ delta_minus->Times10();
+ // We optimized delta_plus to be equal to delta_minus (if they share the
+ // same value). So don't multiply delta_plus if they point to the same
+ // object.
+ if (delta_minus != delta_plus) {
+ delta_plus->Times10();
+ }
+ } else if (in_delta_room_minus && in_delta_room_plus) {
+ // Let's see if 2*numerator < denominator.
+ // If yes, then the next digit would be < 5 and we can round down.
+ int compare = Bignum::PlusCompare(*numerator, *numerator, *denominator);
+ if (compare < 0) {
+ // Remaining digits are less than .5. -> Round down (== do nothing).
+ } else if (compare > 0) {
+ // Remaining digits are more than .5 of denominator. -> Round up.
+ // Note that the last digit could not be a '9' as otherwise the whole
+ // loop would have stopped earlier.
+ // We still have an assert here in case the preconditions were not
+ // satisfied.
+ DOUBLE_CONVERSION_ASSERT(buffer[(*length) - 1] != '9');
+ buffer[(*length) - 1]++;
+ } else {
+ // Halfway case.
+ // TODO(floitsch): need a way to solve half-way cases.
+ // For now let's round towards even (since this is what Gay seems to
+ // do).
+
+ if ((buffer[(*length) - 1] - '0') % 2 == 0) {
+ // Round down => Do nothing.
+ } else {
+ DOUBLE_CONVERSION_ASSERT(buffer[(*length) - 1] != '9');
+ buffer[(*length) - 1]++;
+ }
+ }
+ return;
+ } else if (in_delta_room_minus) {
+ // Round down (== do nothing).
+ return;
+ } else { // in_delta_room_plus
+ // Round up.
+ // Note again that the last digit could not be '9' since this would have
+ // stopped the loop earlier.
+ // We still have an DOUBLE_CONVERSION_ASSERT here, in case the preconditions were not
+ // satisfied.
+ DOUBLE_CONVERSION_ASSERT(buffer[(*length) -1] != '9');
+ buffer[(*length) - 1]++;
+ return;
+ }
+ }
+}
+
+
+// Let v = numerator / denominator < 10.
+// Then we generate 'count' digits of d = x.xxxxx... (without the decimal point)
+// from left to right. Once 'count' digits have been produced we decide wether
+// to round up or down. Remainders of exactly .5 round upwards. Numbers such
+// as 9.999999 propagate a carry all the way, and change the
+// exponent (decimal_point), when rounding upwards.
+static void GenerateCountedDigits(int count, int* decimal_point,
+ Bignum* numerator, Bignum* denominator,
+ Vector<char> buffer, int* length) {
+ DOUBLE_CONVERSION_ASSERT(count >= 0);
+ for (int i = 0; i < count - 1; ++i) {
+ uint16_t digit;
+ digit = numerator->DivideModuloIntBignum(*denominator);
+ DOUBLE_CONVERSION_ASSERT(digit <= 9); // digit is a uint16_t and therefore always positive.
+ // digit = numerator / denominator (integer division).
+ // numerator = numerator % denominator.
+ buffer[i] = static_cast<char>(digit + '0');
+ // Prepare for next iteration.
+ numerator->Times10();
+ }
+ // Generate the last digit.
+ uint16_t digit;
+ digit = numerator->DivideModuloIntBignum(*denominator);
+ if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) {
+ digit++;
+ }
+ DOUBLE_CONVERSION_ASSERT(digit <= 10);
+ buffer[count - 1] = static_cast<char>(digit + '0');
+ // Correct bad digits (in case we had a sequence of '9's). Propagate the
+ // carry until we hat a non-'9' or til we reach the first digit.
+ for (int i = count - 1; i > 0; --i) {
+ if (buffer[i] != '0' + 10) break;
+ buffer[i] = '0';
+ buffer[i - 1]++;
+ }
+ if (buffer[0] == '0' + 10) {
+ // Propagate a carry past the top place.
+ buffer[0] = '1';
+ (*decimal_point)++;
+ }
+ *length = count;
+}
+
+
+// Generates 'requested_digits' after the decimal point. It might omit
+// trailing '0's. If the input number is too small then no digits at all are
+// generated (ex.: 2 fixed digits for 0.00001).
+//
+// Input verifies: 1 <= (numerator + delta) / denominator < 10.
+static void BignumToFixed(int requested_digits, int* decimal_point,
+ Bignum* numerator, Bignum* denominator,
+ Vector<char> buffer, int* length) {
+ // Note that we have to look at more than just the requested_digits, since
+ // a number could be rounded up. Example: v=0.5 with requested_digits=0.
+ // Even though the power of v equals 0 we can't just stop here.
+ if (-(*decimal_point) > requested_digits) {
+ // The number is definitively too small.
+ // Ex: 0.001 with requested_digits == 1.
+ // Set decimal-point to -requested_digits. This is what Gay does.
+ // Note that it should not have any effect anyways since the string is
+ // empty.
+ *decimal_point = -requested_digits;
+ *length = 0;
+ return;
+ } else if (-(*decimal_point) == requested_digits) {
+ // We only need to verify if the number rounds down or up.
+ // Ex: 0.04 and 0.06 with requested_digits == 1.
+ DOUBLE_CONVERSION_ASSERT(*decimal_point == -requested_digits);
+ // Initially the fraction lies in range (1, 10]. Multiply the denominator
+ // by 10 so that we can compare more easily.
+ denominator->Times10();
+ if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) {
+ // If the fraction is >= 0.5 then we have to include the rounded
+ // digit.
+ buffer[0] = '1';
+ *length = 1;
+ (*decimal_point)++;
+ } else {
+ // Note that we caught most of similar cases earlier.
+ *length = 0;
+ }
+ return;
+ } else {
+ // The requested digits correspond to the digits after the point.
+ // The variable 'needed_digits' includes the digits before the point.
+ int needed_digits = (*decimal_point) + requested_digits;
+ GenerateCountedDigits(needed_digits, decimal_point,
+ numerator, denominator,
+ buffer, length);
+ }
+}
+
+
+// Returns an estimation of k such that 10^(k-1) <= v < 10^k where
+// v = f * 2^exponent and 2^52 <= f < 2^53.
+// v is hence a normalized double with the given exponent. The output is an
+// approximation for the exponent of the decimal approimation .digits * 10^k.
+//
+// The result might undershoot by 1 in which case 10^k <= v < 10^k+1.
+// Note: this property holds for v's upper boundary m+ too.
+// 10^k <= m+ < 10^k+1.
+// (see explanation below).
+//
+// Examples:
+// EstimatePower(0) => 16
+// EstimatePower(-52) => 0
+//
+// Note: e >= 0 => EstimatedPower(e) > 0. No similar claim can be made for e<0.
+static int EstimatePower(int exponent) {
+ // This function estimates log10 of v where v = f*2^e (with e == exponent).
+ // Note that 10^floor(log10(v)) <= v, but v <= 10^ceil(log10(v)).
+ // Note that f is bounded by its container size. Let p = 53 (the double's
+ // significand size). Then 2^(p-1) <= f < 2^p.
+ //
+ // Given that log10(v) == log2(v)/log2(10) and e+(len(f)-1) is quite close
+ // to log2(v) the function is simplified to (e+(len(f)-1)/log2(10)).
+ // The computed number undershoots by less than 0.631 (when we compute log3
+ // and not log10).
+ //
+ // Optimization: since we only need an approximated result this computation
+ // can be performed on 64 bit integers. On x86/x64 architecture the speedup is
+ // not really measurable, though.
+ //
+ // Since we want to avoid overshooting we decrement by 1e10 so that
+ // floating-point imprecisions don't affect us.
+ //
+ // Explanation for v's boundary m+: the computation takes advantage of
+ // the fact that 2^(p-1) <= f < 2^p. Boundaries still satisfy this requirement
+ // (even for denormals where the delta can be much more important).
+
+ const double k1Log10 = 0.30102999566398114; // 1/lg(10)
+
+ // For doubles len(f) == 53 (don't forget the hidden bit).
+ const int kSignificandSize = Double::kSignificandSize;
+ double estimate = ceil((exponent + kSignificandSize - 1) * k1Log10 - 1e-10);
+ return static_cast<int>(estimate);
+}
+
+
+// See comments for InitialScaledStartValues.
+static void InitialScaledStartValuesPositiveExponent(
+ uint64_t significand, int exponent,
+ int estimated_power, bool need_boundary_deltas,
+ Bignum* numerator, Bignum* denominator,
+ Bignum* delta_minus, Bignum* delta_plus) {
+ // A positive exponent implies a positive power.
+ DOUBLE_CONVERSION_ASSERT(estimated_power >= 0);
+ // Since the estimated_power is positive we simply multiply the denominator
+ // by 10^estimated_power.
+
+ // numerator = v.
+ numerator->AssignUInt64(significand);
+ numerator->ShiftLeft(exponent);
+ // denominator = 10^estimated_power.
+ denominator->AssignPowerUInt16(10, estimated_power);
+
+ if (need_boundary_deltas) {
+ // Introduce a common denominator so that the deltas to the boundaries are
+ // integers.
+ denominator->ShiftLeft(1);
+ numerator->ShiftLeft(1);
+ // Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common
+ // denominator (of 2) delta_plus equals 2^e.
+ delta_plus->AssignUInt16(1);
+ delta_plus->ShiftLeft(exponent);
+ // Same for delta_minus. The adjustments if f == 2^p-1 are done later.
+ delta_minus->AssignUInt16(1);
+ delta_minus->ShiftLeft(exponent);
+ }
+}
+
+
+// See comments for InitialScaledStartValues
+static void InitialScaledStartValuesNegativeExponentPositivePower(
+ uint64_t significand, int exponent,
+ int estimated_power, bool need_boundary_deltas,
+ Bignum* numerator, Bignum* denominator,
+ Bignum* delta_minus, Bignum* delta_plus) {
+ // v = f * 2^e with e < 0, and with estimated_power >= 0.
+ // This means that e is close to 0 (have a look at how estimated_power is
+ // computed).
+
+ // numerator = significand
+ // since v = significand * 2^exponent this is equivalent to
+ // numerator = v * / 2^-exponent
+ numerator->AssignUInt64(significand);
+ // denominator = 10^estimated_power * 2^-exponent (with exponent < 0)
+ denominator->AssignPowerUInt16(10, estimated_power);
+ denominator->ShiftLeft(-exponent);
+
+ if (need_boundary_deltas) {
+ // Introduce a common denominator so that the deltas to the boundaries are
+ // integers.
+ denominator->ShiftLeft(1);
+ numerator->ShiftLeft(1);
+ // Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common
+ // denominator (of 2) delta_plus equals 2^e.
+ // Given that the denominator already includes v's exponent the distance
+ // to the boundaries is simply 1.
+ delta_plus->AssignUInt16(1);
+ // Same for delta_minus. The adjustments if f == 2^p-1 are done later.
+ delta_minus->AssignUInt16(1);
+ }
+}
+
+
+// See comments for InitialScaledStartValues
+static void InitialScaledStartValuesNegativeExponentNegativePower(
+ uint64_t significand, int exponent,
+ int estimated_power, bool need_boundary_deltas,
+ Bignum* numerator, Bignum* denominator,
+ Bignum* delta_minus, Bignum* delta_plus) {
+ // Instead of multiplying the denominator with 10^estimated_power we
+ // multiply all values (numerator and deltas) by 10^-estimated_power.
+
+ // Use numerator as temporary container for power_ten.
+ Bignum* power_ten = numerator;
+ power_ten->AssignPowerUInt16(10, -estimated_power);
+
+ if (need_boundary_deltas) {
+ // Since power_ten == numerator we must make a copy of 10^estimated_power
+ // before we complete the computation of the numerator.
+ // delta_plus = delta_minus = 10^estimated_power
+ delta_plus->AssignBignum(*power_ten);
+ delta_minus->AssignBignum(*power_ten);
+ }
+
+ // numerator = significand * 2 * 10^-estimated_power
+ // since v = significand * 2^exponent this is equivalent to
+ // numerator = v * 10^-estimated_power * 2 * 2^-exponent.
+ // Remember: numerator has been abused as power_ten. So no need to assign it
+ // to itself.
+ DOUBLE_CONVERSION_ASSERT(numerator == power_ten);
+ numerator->MultiplyByUInt64(significand);
+
+ // denominator = 2 * 2^-exponent with exponent < 0.
+ denominator->AssignUInt16(1);
+ denominator->ShiftLeft(-exponent);
+
+ if (need_boundary_deltas) {
+ // Introduce a common denominator so that the deltas to the boundaries are
+ // integers.
+ numerator->ShiftLeft(1);
+ denominator->ShiftLeft(1);
+ // With this shift the boundaries have their correct value, since
+ // delta_plus = 10^-estimated_power, and
+ // delta_minus = 10^-estimated_power.
+ // These assignments have been done earlier.
+ // The adjustments if f == 2^p-1 (lower boundary is closer) are done later.
+ }
+}
+
+
+// Let v = significand * 2^exponent.
+// Computes v / 10^estimated_power exactly, as a ratio of two bignums, numerator
+// and denominator. The functions GenerateShortestDigits and
+// GenerateCountedDigits will then convert this ratio to its decimal
+// representation d, with the required accuracy.
+// Then d * 10^estimated_power is the representation of v.
+// (Note: the fraction and the estimated_power might get adjusted before
+// generating the decimal representation.)
+//
+// The initial start values consist of:
+// - a scaled numerator: s.t. numerator/denominator == v / 10^estimated_power.
+// - a scaled (common) denominator.
+// optionally (used by GenerateShortestDigits to decide if it has the shortest
+// decimal converting back to v):
+// - v - m-: the distance to the lower boundary.
+// - m+ - v: the distance to the upper boundary.
+//
+// v, m+, m-, and therefore v - m- and m+ - v all share the same denominator.
+//
+// Let ep == estimated_power, then the returned values will satisfy:
+// v / 10^ep = numerator / denominator.
+// v's boundarys m- and m+:
+// m- / 10^ep == v / 10^ep - delta_minus / denominator
+// m+ / 10^ep == v / 10^ep + delta_plus / denominator
+// Or in other words:
+// m- == v - delta_minus * 10^ep / denominator;
+// m+ == v + delta_plus * 10^ep / denominator;
+//
+// Since 10^(k-1) <= v < 10^k (with k == estimated_power)
+// or 10^k <= v < 10^(k+1)
+// we then have 0.1 <= numerator/denominator < 1
+// or 1 <= numerator/denominator < 10
+//
+// It is then easy to kickstart the digit-generation routine.
+//
+// The boundary-deltas are only filled if the mode equals BIGNUM_DTOA_SHORTEST
+// or BIGNUM_DTOA_SHORTEST_SINGLE.
+
+static void InitialScaledStartValues(uint64_t significand,
+ int exponent,
+ bool lower_boundary_is_closer,
+ int estimated_power,
+ bool need_boundary_deltas,
+ Bignum* numerator,
+ Bignum* denominator,
+ Bignum* delta_minus,
+ Bignum* delta_plus) {
+ if (exponent >= 0) {
+ InitialScaledStartValuesPositiveExponent(
+ significand, exponent, estimated_power, need_boundary_deltas,
+ numerator, denominator, delta_minus, delta_plus);
+ } else if (estimated_power >= 0) {
+ InitialScaledStartValuesNegativeExponentPositivePower(
+ significand, exponent, estimated_power, need_boundary_deltas,
+ numerator, denominator, delta_minus, delta_plus);
+ } else {
+ InitialScaledStartValuesNegativeExponentNegativePower(
+ significand, exponent, estimated_power, need_boundary_deltas,
+ numerator, denominator, delta_minus, delta_plus);
+ }
+
+ if (need_boundary_deltas && lower_boundary_is_closer) {
+ // The lower boundary is closer at half the distance of "normal" numbers.
+ // Increase the common denominator and adapt all but the delta_minus.
+ denominator->ShiftLeft(1); // *2
+ numerator->ShiftLeft(1); // *2
+ delta_plus->ShiftLeft(1); // *2
+ }
+}
+
+
+// This routine multiplies numerator/denominator so that its values lies in the
+// range 1-10. That is after a call to this function we have:
+// 1 <= (numerator + delta_plus) /denominator < 10.
+// Let numerator the input before modification and numerator' the argument
+// after modification, then the output-parameter decimal_point is such that
+// numerator / denominator * 10^estimated_power ==
+// numerator' / denominator' * 10^(decimal_point - 1)
+// In some cases estimated_power was too low, and this is already the case. We
+// then simply adjust the power so that 10^(k-1) <= v < 10^k (with k ==
+// estimated_power) but do not touch the numerator or denominator.
+// Otherwise the routine multiplies the numerator and the deltas by 10.
+static void FixupMultiply10(int estimated_power, bool is_even,
+ int* decimal_point,
+ Bignum* numerator, Bignum* denominator,
+ Bignum* delta_minus, Bignum* delta_plus) {
+ bool in_range;
+ if (is_even) {
+ // For IEEE doubles half-way cases (in decimal system numbers ending with 5)
+ // are rounded to the closest floating-point number with even significand.
+ in_range = Bignum::PlusCompare(*numerator, *delta_plus, *denominator) >= 0;
+ } else {
+ in_range = Bignum::PlusCompare(*numerator, *delta_plus, *denominator) > 0;
+ }
+ if (in_range) {
+ // Since numerator + delta_plus >= denominator we already have
+ // 1 <= numerator/denominator < 10. Simply update the estimated_power.
+ *decimal_point = estimated_power + 1;
+ } else {
+ *decimal_point = estimated_power;
+ numerator->Times10();
+ if (Bignum::Equal(*delta_minus, *delta_plus)) {
+ delta_minus->Times10();
+ delta_plus->AssignBignum(*delta_minus);
+ } else {
+ delta_minus->Times10();
+ delta_plus->Times10();
+ }
+ }
+}
+
+} // namespace double_conversion
+
+// ICU PATCH: Close ICU namespace
+U_NAMESPACE_END
+#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
diff --git a/contrib/libs/icu/i18n/double-conversion-bignum-dtoa.h b/contrib/libs/icu/i18n/double-conversion-bignum-dtoa.h
index edc21b0f2e..f094236a4e 100644
--- a/contrib/libs/icu/i18n/double-conversion-bignum-dtoa.h
+++ b/contrib/libs/icu/i18n/double-conversion-bignum-dtoa.h
@@ -1,102 +1,102 @@
-// © 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_BIGNUM_DTOA_H_
-#define DOUBLE_CONVERSION_BIGNUM_DTOA_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 {
-
-enum BignumDtoaMode {
- // Return the shortest correct representation.
- // For example the output of 0.299999999999999988897 is (the less accurate but
- // correct) 0.3.
- BIGNUM_DTOA_SHORTEST,
- // Same as BIGNUM_DTOA_SHORTEST but for single-precision floats.
- BIGNUM_DTOA_SHORTEST_SINGLE,
- // Return a fixed number of digits after the decimal point.
- // For instance fixed(0.1, 4) becomes 0.1000
- // If the input number is big, the output will be big.
- BIGNUM_DTOA_FIXED,
- // Return a fixed number of digits, no matter what the exponent is.
- BIGNUM_DTOA_PRECISION
-};
-
-// Converts the given double 'v' to ascii.
-// The result should be interpreted as buffer * 10^(point-length).
-// The buffer will be null-terminated.
-//
-// The input v must be > 0 and different from NaN, and Infinity.
-//
-// The output depends on the given mode:
-// - SHORTEST: produce the least amount of digits for which the internal
-// identity requirement is still satisfied. If the digits are printed
-// (together with the correct exponent) then reading this number will give
-// 'v' again. The buffer will choose the representation that is closest to
-// 'v'. If there are two at the same distance, than the number is round up.
-// In this mode the 'requested_digits' parameter is ignored.
-// - FIXED: produces digits necessary to print a given number with
-// 'requested_digits' digits after the decimal point. The produced digits
-// might be too short in which case the caller has to fill the gaps with '0's.
-// Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2.
-// Halfway cases are rounded up. The call toFixed(0.15, 2) thus returns
-// buffer="2", point=0.
-// Note: the length of the returned buffer has no meaning wrt the significance
-// of its digits. That is, just because it contains '0's does not mean that
-// any other digit would not satisfy the internal identity requirement.
-// - PRECISION: produces 'requested_digits' where the first digit is not '0'.
-// Even though the length of produced digits usually equals
-// 'requested_digits', the function is allowed to return fewer digits, in
-// which case the caller has to fill the missing digits with '0's.
-// Halfway cases are again rounded up.
-// 'BignumDtoa' expects the given buffer to be big enough to hold all digits
-// and a terminating null-character.
-void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits,
- Vector<char> buffer, int* length, int* point);
-
-} // namespace double_conversion
-
-// ICU PATCH: Close ICU namespace
-U_NAMESPACE_END
-
-#endif // DOUBLE_CONVERSION_BIGNUM_DTOA_H_
-#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
+// © 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_BIGNUM_DTOA_H_
+#define DOUBLE_CONVERSION_BIGNUM_DTOA_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 {
+
+enum BignumDtoaMode {
+ // Return the shortest correct representation.
+ // For example the output of 0.299999999999999988897 is (the less accurate but
+ // correct) 0.3.
+ BIGNUM_DTOA_SHORTEST,
+ // Same as BIGNUM_DTOA_SHORTEST but for single-precision floats.
+ BIGNUM_DTOA_SHORTEST_SINGLE,
+ // Return a fixed number of digits after the decimal point.
+ // For instance fixed(0.1, 4) becomes 0.1000
+ // If the input number is big, the output will be big.
+ BIGNUM_DTOA_FIXED,
+ // Return a fixed number of digits, no matter what the exponent is.
+ BIGNUM_DTOA_PRECISION
+};
+
+// Converts the given double 'v' to ascii.
+// The result should be interpreted as buffer * 10^(point-length).
+// The buffer will be null-terminated.
+//
+// The input v must be > 0 and different from NaN, and Infinity.
+//
+// The output depends on the given mode:
+// - SHORTEST: produce the least amount of digits for which the internal
+// identity requirement is still satisfied. If the digits are printed
+// (together with the correct exponent) then reading this number will give
+// 'v' again. The buffer will choose the representation that is closest to
+// 'v'. If there are two at the same distance, than the number is round up.
+// In this mode the 'requested_digits' parameter is ignored.
+// - FIXED: produces digits necessary to print a given number with
+// 'requested_digits' digits after the decimal point. The produced digits
+// might be too short in which case the caller has to fill the gaps with '0's.
+// Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2.
+// Halfway cases are rounded up. The call toFixed(0.15, 2) thus returns
+// buffer="2", point=0.
+// Note: the length of the returned buffer has no meaning wrt the significance
+// of its digits. That is, just because it contains '0's does not mean that
+// any other digit would not satisfy the internal identity requirement.
+// - PRECISION: produces 'requested_digits' where the first digit is not '0'.
+// Even though the length of produced digits usually equals
+// 'requested_digits', the function is allowed to return fewer digits, in
+// which case the caller has to fill the missing digits with '0's.
+// Halfway cases are again rounded up.
+// 'BignumDtoa' expects the given buffer to be big enough to hold all digits
+// and a terminating null-character.
+void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits,
+ Vector<char> buffer, int* length, int* point);
+
+} // namespace double_conversion
+
+// ICU PATCH: Close ICU namespace
+U_NAMESPACE_END
+
+#endif // DOUBLE_CONVERSION_BIGNUM_DTOA_H_
+#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
diff --git a/contrib/libs/icu/i18n/double-conversion-bignum.cpp b/contrib/libs/icu/i18n/double-conversion-bignum.cpp
index 996d75c9f6..025973eaa2 100644
--- a/contrib/libs/icu/i18n/double-conversion-bignum.cpp
+++ b/contrib/libs/icu/i18n/double-conversion-bignum.cpp
@@ -1,814 +1,814 @@
-// © 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 <algorithm>
-#include <cstring>
-
-// ICU PATCH: Customize header file paths for ICU.
-
-#include "double-conversion-bignum.h"
-#include "double-conversion-utils.h"
-
-// ICU PATCH: Wrap in ICU namespace
-U_NAMESPACE_BEGIN
-
-namespace double_conversion {
-
-Bignum::Chunk& Bignum::RawBigit(const int index) {
- DOUBLE_CONVERSION_ASSERT(static_cast<unsigned>(index) < kBigitCapacity);
- return bigits_buffer_[index];
-}
-
-
-const Bignum::Chunk& Bignum::RawBigit(const int index) const {
- DOUBLE_CONVERSION_ASSERT(static_cast<unsigned>(index) < kBigitCapacity);
- return bigits_buffer_[index];
-}
-
-
-template<typename S>
-static int BitSize(const S value) {
- (void) value; // Mark variable as used.
- return 8 * sizeof(value);
-}
-
-// Guaranteed to lie in one Bigit.
-void Bignum::AssignUInt16(const uint16_t value) {
- DOUBLE_CONVERSION_ASSERT(kBigitSize >= BitSize(value));
- Zero();
- if (value > 0) {
- RawBigit(0) = value;
- used_bigits_ = 1;
- }
-}
-
-
-void Bignum::AssignUInt64(uint64_t value) {
- Zero();
- for(int i = 0; value > 0; ++i) {
- RawBigit(i) = value & kBigitMask;
- value >>= kBigitSize;
- ++used_bigits_;
- }
-}
-
-
-void Bignum::AssignBignum(const Bignum& other) {
- exponent_ = other.exponent_;
- for (int i = 0; i < other.used_bigits_; ++i) {
- RawBigit(i) = other.RawBigit(i);
- }
- used_bigits_ = other.used_bigits_;
-}
-
-
-static uint64_t ReadUInt64(const Vector<const char> buffer,
- const int from,
- const int digits_to_read) {
- uint64_t result = 0;
- for (int i = from; i < from + digits_to_read; ++i) {
- const int digit = buffer[i] - '0';
- DOUBLE_CONVERSION_ASSERT(0 <= digit && digit <= 9);
- result = result * 10 + digit;
- }
- return result;
-}
-
-
-void Bignum::AssignDecimalString(const Vector<const char> value) {
- // 2^64 = 18446744073709551616 > 10^19
- static const int kMaxUint64DecimalDigits = 19;
- Zero();
- int length = value.length();
- unsigned pos = 0;
- // Let's just say that each digit needs 4 bits.
- while (length >= kMaxUint64DecimalDigits) {
- const uint64_t digits = ReadUInt64(value, pos, kMaxUint64DecimalDigits);
- pos += kMaxUint64DecimalDigits;
- length -= kMaxUint64DecimalDigits;
- MultiplyByPowerOfTen(kMaxUint64DecimalDigits);
- AddUInt64(digits);
- }
- const uint64_t digits = ReadUInt64(value, pos, length);
- MultiplyByPowerOfTen(length);
- AddUInt64(digits);
- Clamp();
-}
-
-
-static uint64_t HexCharValue(const int c) {
- if ('0' <= c && c <= '9') {
- return c - '0';
- }
- if ('a' <= c && c <= 'f') {
- return 10 + c - 'a';
- }
- DOUBLE_CONVERSION_ASSERT('A' <= c && c <= 'F');
- return 10 + c - 'A';
-}
-
-
-// Unlike AssignDecimalString(), this function is "only" used
-// for unit-tests and therefore not performance critical.
-void Bignum::AssignHexString(Vector<const char> value) {
- Zero();
- // Required capacity could be reduced by ignoring leading zeros.
- EnsureCapacity(((value.length() * 4) + kBigitSize - 1) / kBigitSize);
- DOUBLE_CONVERSION_ASSERT(sizeof(uint64_t) * 8 >= kBigitSize + 4); // TODO: static_assert
- // Accumulates converted hex digits until at least kBigitSize bits.
- // Works with non-factor-of-four kBigitSizes.
- uint64_t tmp = 0; // Accumulates converted hex digits until at least
- for (int cnt = 0; !value.is_empty(); value.pop_back()) {
- tmp |= (HexCharValue(value.last()) << cnt);
- if ((cnt += 4) >= kBigitSize) {
- RawBigit(used_bigits_++) = (tmp & kBigitMask);
- cnt -= kBigitSize;
- tmp >>= kBigitSize;
- }
- }
- if (tmp > 0) {
- RawBigit(used_bigits_++) = tmp;
- }
- Clamp();
-}
-
-
-void Bignum::AddUInt64(const uint64_t operand) {
- if (operand == 0) {
- return;
- }
- Bignum other;
- other.AssignUInt64(operand);
- AddBignum(other);
-}
-
-
-void Bignum::AddBignum(const Bignum& other) {
- DOUBLE_CONVERSION_ASSERT(IsClamped());
- DOUBLE_CONVERSION_ASSERT(other.IsClamped());
-
- // If this has a greater exponent than other append zero-bigits to this.
- // After this call exponent_ <= other.exponent_.
- Align(other);
-
- // There are two possibilities:
- // aaaaaaaaaaa 0000 (where the 0s represent a's exponent)
- // bbbbb 00000000
- // ----------------
- // ccccccccccc 0000
- // or
- // aaaaaaaaaa 0000
- // bbbbbbbbb 0000000
- // -----------------
- // cccccccccccc 0000
- // In both cases we might need a carry bigit.
-
- EnsureCapacity(1 + (std::max)(BigitLength(), other.BigitLength()) - exponent_);
- Chunk carry = 0;
- int bigit_pos = other.exponent_ - exponent_;
- DOUBLE_CONVERSION_ASSERT(bigit_pos >= 0);
- for (int i = used_bigits_; i < bigit_pos; ++i) {
- RawBigit(i) = 0;
- }
- for (int i = 0; i < other.used_bigits_; ++i) {
- const Chunk my = (bigit_pos < used_bigits_) ? RawBigit(bigit_pos) : 0;
- const Chunk sum = my + other.RawBigit(i) + carry;
- RawBigit(bigit_pos) = sum & kBigitMask;
- carry = sum >> kBigitSize;
- ++bigit_pos;
- }
- while (carry != 0) {
- const Chunk my = (bigit_pos < used_bigits_) ? RawBigit(bigit_pos) : 0;
- const Chunk sum = my + carry;
- RawBigit(bigit_pos) = sum & kBigitMask;
- carry = sum >> kBigitSize;
- ++bigit_pos;
- }
- used_bigits_ = (std::max)(bigit_pos, static_cast<int>(used_bigits_));
- DOUBLE_CONVERSION_ASSERT(IsClamped());
-}
-
-
-void Bignum::SubtractBignum(const Bignum& other) {
- DOUBLE_CONVERSION_ASSERT(IsClamped());
- DOUBLE_CONVERSION_ASSERT(other.IsClamped());
- // We require this to be bigger than other.
- DOUBLE_CONVERSION_ASSERT(LessEqual(other, *this));
-
- Align(other);
-
- const int offset = other.exponent_ - exponent_;
- Chunk borrow = 0;
- int i;
- for (i = 0; i < other.used_bigits_; ++i) {
- DOUBLE_CONVERSION_ASSERT((borrow == 0) || (borrow == 1));
- const Chunk difference = RawBigit(i + offset) - other.RawBigit(i) - borrow;
- RawBigit(i + offset) = difference & kBigitMask;
- borrow = difference >> (kChunkSize - 1);
- }
- while (borrow != 0) {
- const Chunk difference = RawBigit(i + offset) - borrow;
- RawBigit(i + offset) = difference & kBigitMask;
- borrow = difference >> (kChunkSize - 1);
- ++i;
- }
- Clamp();
-}
-
-
-void Bignum::ShiftLeft(const int shift_amount) {
- if (used_bigits_ == 0) {
- return;
- }
- exponent_ += (shift_amount / kBigitSize);
- const int local_shift = shift_amount % kBigitSize;
- EnsureCapacity(used_bigits_ + 1);
- BigitsShiftLeft(local_shift);
-}
-
-
-void Bignum::MultiplyByUInt32(const uint32_t factor) {
- if (factor == 1) {
- return;
- }
- if (factor == 0) {
- Zero();
- return;
- }
- if (used_bigits_ == 0) {
- return;
- }
- // The product of a bigit with the factor is of size kBigitSize + 32.
- // Assert that this number + 1 (for the carry) fits into double chunk.
- DOUBLE_CONVERSION_ASSERT(kDoubleChunkSize >= kBigitSize + 32 + 1);
- DoubleChunk carry = 0;
- for (int i = 0; i < used_bigits_; ++i) {
- const DoubleChunk product = static_cast<DoubleChunk>(factor) * RawBigit(i) + carry;
- RawBigit(i) = static_cast<Chunk>(product & kBigitMask);
- carry = (product >> kBigitSize);
- }
- while (carry != 0) {
- EnsureCapacity(used_bigits_ + 1);
- RawBigit(used_bigits_) = carry & kBigitMask;
- used_bigits_++;
- carry >>= kBigitSize;
- }
-}
-
-
-void Bignum::MultiplyByUInt64(const uint64_t factor) {
- if (factor == 1) {
- return;
- }
- if (factor == 0) {
- Zero();
- return;
- }
- if (used_bigits_ == 0) {
- return;
- }
- DOUBLE_CONVERSION_ASSERT(kBigitSize < 32);
- uint64_t carry = 0;
- const uint64_t low = factor & 0xFFFFFFFF;
- const uint64_t high = factor >> 32;
- for (int i = 0; i < used_bigits_; ++i) {
- const uint64_t product_low = low * RawBigit(i);
- const uint64_t product_high = high * RawBigit(i);
- const uint64_t tmp = (carry & kBigitMask) + product_low;
- RawBigit(i) = tmp & kBigitMask;
- carry = (carry >> kBigitSize) + (tmp >> kBigitSize) +
- (product_high << (32 - kBigitSize));
- }
- while (carry != 0) {
- EnsureCapacity(used_bigits_ + 1);
- RawBigit(used_bigits_) = carry & kBigitMask;
- used_bigits_++;
- carry >>= kBigitSize;
- }
-}
-
-
-void Bignum::MultiplyByPowerOfTen(const int exponent) {
- static const uint64_t kFive27 = DOUBLE_CONVERSION_UINT64_2PART_C(0x6765c793, fa10079d);
- static const uint16_t kFive1 = 5;
- static const uint16_t kFive2 = kFive1 * 5;
- static const uint16_t kFive3 = kFive2 * 5;
- static const uint16_t kFive4 = kFive3 * 5;
- static const uint16_t kFive5 = kFive4 * 5;
- static const uint16_t kFive6 = kFive5 * 5;
- static const uint32_t kFive7 = kFive6 * 5;
- static const uint32_t kFive8 = kFive7 * 5;
- static const uint32_t kFive9 = kFive8 * 5;
- static const uint32_t kFive10 = kFive9 * 5;
- static const uint32_t kFive11 = kFive10 * 5;
- static const uint32_t kFive12 = kFive11 * 5;
- static const uint32_t kFive13 = kFive12 * 5;
- static const uint32_t kFive1_to_12[] =
- { kFive1, kFive2, kFive3, kFive4, kFive5, kFive6,
- kFive7, kFive8, kFive9, kFive10, kFive11, kFive12 };
-
- DOUBLE_CONVERSION_ASSERT(exponent >= 0);
-
- if (exponent == 0) {
- return;
- }
- if (used_bigits_ == 0) {
- return;
- }
- // We shift by exponent at the end just before returning.
- int remaining_exponent = exponent;
- while (remaining_exponent >= 27) {
- MultiplyByUInt64(kFive27);
- remaining_exponent -= 27;
- }
- while (remaining_exponent >= 13) {
- MultiplyByUInt32(kFive13);
- remaining_exponent -= 13;
- }
- if (remaining_exponent > 0) {
- MultiplyByUInt32(kFive1_to_12[remaining_exponent - 1]);
- }
- ShiftLeft(exponent);
-}
-
-
-void Bignum::Square() {
- DOUBLE_CONVERSION_ASSERT(IsClamped());
- const int product_length = 2 * used_bigits_;
- EnsureCapacity(product_length);
-
- // Comba multiplication: compute each column separately.
- // Example: r = a2a1a0 * b2b1b0.
- // r = 1 * a0b0 +
- // 10 * (a1b0 + a0b1) +
- // 100 * (a2b0 + a1b1 + a0b2) +
- // 1000 * (a2b1 + a1b2) +
- // 10000 * a2b2
- //
- // In the worst case we have to accumulate nb-digits products of digit*digit.
- //
- // Assert that the additional number of bits in a DoubleChunk are enough to
- // sum up used_digits of Bigit*Bigit.
- if ((1 << (2 * (kChunkSize - kBigitSize))) <= used_bigits_) {
- DOUBLE_CONVERSION_UNIMPLEMENTED();
- }
- DoubleChunk accumulator = 0;
- // First shift the digits so we don't overwrite them.
- const int copy_offset = used_bigits_;
- for (int i = 0; i < used_bigits_; ++i) {
- RawBigit(copy_offset + i) = RawBigit(i);
- }
- // We have two loops to avoid some 'if's in the loop.
- for (int i = 0; i < used_bigits_; ++i) {
- // Process temporary digit i with power i.
- // The sum of the two indices must be equal to i.
- int bigit_index1 = i;
- int bigit_index2 = 0;
- // Sum all of the sub-products.
- while (bigit_index1 >= 0) {
- const Chunk chunk1 = RawBigit(copy_offset + bigit_index1);
- const Chunk chunk2 = RawBigit(copy_offset + bigit_index2);
- accumulator += static_cast<DoubleChunk>(chunk1) * chunk2;
- bigit_index1--;
- bigit_index2++;
- }
- RawBigit(i) = static_cast<Chunk>(accumulator) & kBigitMask;
- accumulator >>= kBigitSize;
- }
- for (int i = used_bigits_; i < product_length; ++i) {
- int bigit_index1 = used_bigits_ - 1;
- int bigit_index2 = i - bigit_index1;
- // Invariant: sum of both indices is again equal to i.
- // Inner loop runs 0 times on last iteration, emptying accumulator.
- while (bigit_index2 < used_bigits_) {
- const Chunk chunk1 = RawBigit(copy_offset + bigit_index1);
- const Chunk chunk2 = RawBigit(copy_offset + bigit_index2);
- accumulator += static_cast<DoubleChunk>(chunk1) * chunk2;
- bigit_index1--;
- bigit_index2++;
- }
- // The overwritten RawBigit(i) will never be read in further loop iterations,
- // because bigit_index1 and bigit_index2 are always greater
- // than i - used_bigits_.
- RawBigit(i) = static_cast<Chunk>(accumulator) & kBigitMask;
- accumulator >>= kBigitSize;
- }
- // Since the result was guaranteed to lie inside the number the
- // accumulator must be 0 now.
- DOUBLE_CONVERSION_ASSERT(accumulator == 0);
-
- // Don't forget to update the used_digits and the exponent.
- used_bigits_ = product_length;
- exponent_ *= 2;
- Clamp();
-}
-
-
-void Bignum::AssignPowerUInt16(uint16_t base, const int power_exponent) {
- DOUBLE_CONVERSION_ASSERT(base != 0);
- DOUBLE_CONVERSION_ASSERT(power_exponent >= 0);
- if (power_exponent == 0) {
- AssignUInt16(1);
- return;
- }
- Zero();
- int shifts = 0;
- // We expect base to be in range 2-32, and most often to be 10.
- // It does not make much sense to implement different algorithms for counting
- // the bits.
- while ((base & 1) == 0) {
- base >>= 1;
- shifts++;
- }
- int bit_size = 0;
- int tmp_base = base;
- while (tmp_base != 0) {
- tmp_base >>= 1;
- bit_size++;
- }
- const int final_size = bit_size * power_exponent;
- // 1 extra bigit for the shifting, and one for rounded final_size.
- EnsureCapacity(final_size / kBigitSize + 2);
-
- // Left to Right exponentiation.
- int mask = 1;
- while (power_exponent >= mask) mask <<= 1;
-
- // The mask is now pointing to the bit above the most significant 1-bit of
- // power_exponent.
- // Get rid of first 1-bit;
- mask >>= 2;
- uint64_t this_value = base;
-
- bool delayed_multiplication = false;
- const uint64_t max_32bits = 0xFFFFFFFF;
- while (mask != 0 && this_value <= max_32bits) {
- this_value = this_value * this_value;
- // Verify that there is enough space in this_value to perform the
- // multiplication. The first bit_size bits must be 0.
- if ((power_exponent & mask) != 0) {
- DOUBLE_CONVERSION_ASSERT(bit_size > 0);
- const uint64_t base_bits_mask =
- ~((static_cast<uint64_t>(1) << (64 - bit_size)) - 1);
- const bool high_bits_zero = (this_value & base_bits_mask) == 0;
- if (high_bits_zero) {
- this_value *= base;
- } else {
- delayed_multiplication = true;
- }
- }
- mask >>= 1;
- }
- AssignUInt64(this_value);
- if (delayed_multiplication) {
- MultiplyByUInt32(base);
- }
-
- // Now do the same thing as a bignum.
- while (mask != 0) {
- Square();
- if ((power_exponent & mask) != 0) {
- MultiplyByUInt32(base);
- }
- mask >>= 1;
- }
-
- // And finally add the saved shifts.
- ShiftLeft(shifts * power_exponent);
-}
-
-
-// Precondition: this/other < 16bit.
-uint16_t Bignum::DivideModuloIntBignum(const Bignum& other) {
- DOUBLE_CONVERSION_ASSERT(IsClamped());
- DOUBLE_CONVERSION_ASSERT(other.IsClamped());
- DOUBLE_CONVERSION_ASSERT(other.used_bigits_ > 0);
-
- // Easy case: if we have less digits than the divisor than the result is 0.
- // Note: this handles the case where this == 0, too.
- if (BigitLength() < other.BigitLength()) {
- return 0;
- }
-
- Align(other);
-
- uint16_t result = 0;
-
- // Start by removing multiples of 'other' until both numbers have the same
- // number of digits.
- while (BigitLength() > other.BigitLength()) {
- // This naive approach is extremely inefficient if `this` divided by other
- // is big. This function is implemented for doubleToString where
- // the result should be small (less than 10).
- DOUBLE_CONVERSION_ASSERT(other.RawBigit(other.used_bigits_ - 1) >= ((1 << kBigitSize) / 16));
- DOUBLE_CONVERSION_ASSERT(RawBigit(used_bigits_ - 1) < 0x10000);
- // Remove the multiples of the first digit.
- // Example this = 23 and other equals 9. -> Remove 2 multiples.
- result += static_cast<uint16_t>(RawBigit(used_bigits_ - 1));
- SubtractTimes(other, RawBigit(used_bigits_ - 1));
- }
-
- DOUBLE_CONVERSION_ASSERT(BigitLength() == other.BigitLength());
-
- // Both bignums are at the same length now.
- // Since other has more than 0 digits we know that the access to
- // RawBigit(used_bigits_ - 1) is safe.
- const Chunk this_bigit = RawBigit(used_bigits_ - 1);
- const Chunk other_bigit = other.RawBigit(other.used_bigits_ - 1);
-
- if (other.used_bigits_ == 1) {
- // Shortcut for easy (and common) case.
- int quotient = this_bigit / other_bigit;
- RawBigit(used_bigits_ - 1) = this_bigit - other_bigit * quotient;
- DOUBLE_CONVERSION_ASSERT(quotient < 0x10000);
- result += static_cast<uint16_t>(quotient);
- Clamp();
- return result;
- }
-
- const int division_estimate = this_bigit / (other_bigit + 1);
- DOUBLE_CONVERSION_ASSERT(division_estimate < 0x10000);
- result += static_cast<uint16_t>(division_estimate);
- SubtractTimes(other, division_estimate);
-
- if (other_bigit * (division_estimate + 1) > this_bigit) {
- // No need to even try to subtract. Even if other's remaining digits were 0
- // another subtraction would be too much.
- return result;
- }
-
- while (LessEqual(other, *this)) {
- SubtractBignum(other);
- result++;
- }
- return result;
-}
-
-
-template<typename S>
-static int SizeInHexChars(S number) {
- DOUBLE_CONVERSION_ASSERT(number > 0);
- int result = 0;
- while (number != 0) {
- number >>= 4;
- result++;
- }
- return result;
-}
-
-
-static char HexCharOfValue(const int value) {
- DOUBLE_CONVERSION_ASSERT(0 <= value && value <= 16);
- if (value < 10) {
- return static_cast<char>(value + '0');
- }
- return static_cast<char>(value - 10 + 'A');
-}
-
-
-bool Bignum::ToHexString(char* buffer, const int buffer_size) const {
- DOUBLE_CONVERSION_ASSERT(IsClamped());
- // Each bigit must be printable as separate hex-character.
- DOUBLE_CONVERSION_ASSERT(kBigitSize % 4 == 0);
- static const int kHexCharsPerBigit = kBigitSize / 4;
-
- if (used_bigits_ == 0) {
- if (buffer_size < 2) {
- return false;
- }
- buffer[0] = '0';
- buffer[1] = '\0';
- return true;
- }
- // We add 1 for the terminating '\0' character.
- const int needed_chars = (BigitLength() - 1) * kHexCharsPerBigit +
- SizeInHexChars(RawBigit(used_bigits_ - 1)) + 1;
- if (needed_chars > buffer_size) {
- return false;
- }
- int string_index = needed_chars - 1;
- buffer[string_index--] = '\0';
- for (int i = 0; i < exponent_; ++i) {
- for (int j = 0; j < kHexCharsPerBigit; ++j) {
- buffer[string_index--] = '0';
- }
- }
- for (int i = 0; i < used_bigits_ - 1; ++i) {
- Chunk current_bigit = RawBigit(i);
- for (int j = 0; j < kHexCharsPerBigit; ++j) {
- buffer[string_index--] = HexCharOfValue(current_bigit & 0xF);
- current_bigit >>= 4;
- }
- }
- // And finally the last bigit.
- Chunk most_significant_bigit = RawBigit(used_bigits_ - 1);
- while (most_significant_bigit != 0) {
- buffer[string_index--] = HexCharOfValue(most_significant_bigit & 0xF);
- most_significant_bigit >>= 4;
- }
- return true;
-}
-
-
-Bignum::Chunk Bignum::BigitOrZero(const int index) const {
- if (index >= BigitLength()) {
- return 0;
- }
- if (index < exponent_) {
- return 0;
- }
- return RawBigit(index - exponent_);
-}
-
-
-int Bignum::Compare(const Bignum& a, const Bignum& b) {
- DOUBLE_CONVERSION_ASSERT(a.IsClamped());
- DOUBLE_CONVERSION_ASSERT(b.IsClamped());
- const int bigit_length_a = a.BigitLength();
- const int bigit_length_b = b.BigitLength();
- if (bigit_length_a < bigit_length_b) {
- return -1;
- }
- if (bigit_length_a > bigit_length_b) {
- return +1;
- }
- for (int i = bigit_length_a - 1; i >= (std::min)(a.exponent_, b.exponent_); --i) {
- const Chunk bigit_a = a.BigitOrZero(i);
- const Chunk bigit_b = b.BigitOrZero(i);
- if (bigit_a < bigit_b) {
- return -1;
- }
- if (bigit_a > bigit_b) {
- return +1;
- }
- // Otherwise they are equal up to this digit. Try the next digit.
- }
- return 0;
-}
-
-
-int Bignum::PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c) {
- DOUBLE_CONVERSION_ASSERT(a.IsClamped());
- DOUBLE_CONVERSION_ASSERT(b.IsClamped());
- DOUBLE_CONVERSION_ASSERT(c.IsClamped());
- if (a.BigitLength() < b.BigitLength()) {
- return PlusCompare(b, a, c);
- }
- if (a.BigitLength() + 1 < c.BigitLength()) {
- return -1;
- }
- if (a.BigitLength() > c.BigitLength()) {
- return +1;
- }
- // The exponent encodes 0-bigits. So if there are more 0-digits in 'a' than
- // 'b' has digits, then the bigit-length of 'a'+'b' must be equal to the one
- // of 'a'.
- if (a.exponent_ >= b.BigitLength() && a.BigitLength() < c.BigitLength()) {
- return -1;
- }
-
- Chunk borrow = 0;
- // Starting at min_exponent all digits are == 0. So no need to compare them.
- const int min_exponent = (std::min)((std::min)(a.exponent_, b.exponent_), c.exponent_);
- for (int i = c.BigitLength() - 1; i >= min_exponent; --i) {
- const Chunk chunk_a = a.BigitOrZero(i);
- const Chunk chunk_b = b.BigitOrZero(i);
- const Chunk chunk_c = c.BigitOrZero(i);
- const Chunk sum = chunk_a + chunk_b;
- if (sum > chunk_c + borrow) {
- return +1;
- } else {
- borrow = chunk_c + borrow - sum;
- if (borrow > 1) {
- return -1;
- }
- borrow <<= kBigitSize;
- }
- }
- if (borrow == 0) {
- return 0;
- }
- return -1;
-}
-
-
-void Bignum::Clamp() {
- while (used_bigits_ > 0 && RawBigit(used_bigits_ - 1) == 0) {
- used_bigits_--;
- }
- if (used_bigits_ == 0) {
- // Zero.
- exponent_ = 0;
- }
-}
-
-
-void Bignum::Align(const Bignum& other) {
- if (exponent_ > other.exponent_) {
- // If "X" represents a "hidden" bigit (by the exponent) then we are in the
- // following case (a == this, b == other):
- // a: aaaaaaXXXX or a: aaaaaXXX
- // b: bbbbbbX b: bbbbbbbbXX
- // We replace some of the hidden digits (X) of a with 0 digits.
- // a: aaaaaa000X or a: aaaaa0XX
- const int zero_bigits = exponent_ - other.exponent_;
- EnsureCapacity(used_bigits_ + zero_bigits);
- for (int i = used_bigits_ - 1; i >= 0; --i) {
- RawBigit(i + zero_bigits) = RawBigit(i);
- }
- for (int i = 0; i < zero_bigits; ++i) {
- RawBigit(i) = 0;
- }
- used_bigits_ += zero_bigits;
- exponent_ -= zero_bigits;
-
- DOUBLE_CONVERSION_ASSERT(used_bigits_ >= 0);
- DOUBLE_CONVERSION_ASSERT(exponent_ >= 0);
- }
-}
-
-
-void Bignum::BigitsShiftLeft(const int shift_amount) {
- DOUBLE_CONVERSION_ASSERT(shift_amount < kBigitSize);
- DOUBLE_CONVERSION_ASSERT(shift_amount >= 0);
- Chunk carry = 0;
- for (int i = 0; i < used_bigits_; ++i) {
- const Chunk new_carry = RawBigit(i) >> (kBigitSize - shift_amount);
- RawBigit(i) = ((RawBigit(i) << shift_amount) + carry) & kBigitMask;
- carry = new_carry;
- }
- if (carry != 0) {
- RawBigit(used_bigits_) = carry;
- used_bigits_++;
- }
-}
-
-
-void Bignum::SubtractTimes(const Bignum& other, const int factor) {
- DOUBLE_CONVERSION_ASSERT(exponent_ <= other.exponent_);
- if (factor < 3) {
- for (int i = 0; i < factor; ++i) {
- SubtractBignum(other);
- }
- return;
- }
- Chunk borrow = 0;
- const int exponent_diff = other.exponent_ - exponent_;
- for (int i = 0; i < other.used_bigits_; ++i) {
- const DoubleChunk product = static_cast<DoubleChunk>(factor) * other.RawBigit(i);
- const DoubleChunk remove = borrow + product;
- const Chunk difference = RawBigit(i + exponent_diff) - (remove & kBigitMask);
- RawBigit(i + exponent_diff) = difference & kBigitMask;
- borrow = static_cast<Chunk>((difference >> (kChunkSize - 1)) +
- (remove >> kBigitSize));
- }
- for (int i = other.used_bigits_ + exponent_diff; i < used_bigits_; ++i) {
- if (borrow == 0) {
- return;
- }
- const Chunk difference = RawBigit(i) - borrow;
- RawBigit(i) = difference & kBigitMask;
- borrow = difference >> (kChunkSize - 1);
- }
- Clamp();
-}
-
-
-} // namespace double_conversion
-
-// ICU PATCH: Close ICU namespace
-U_NAMESPACE_END
-#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
+// © 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 <algorithm>
+#include <cstring>
+
+// ICU PATCH: Customize header file paths for ICU.
+
+#include "double-conversion-bignum.h"
+#include "double-conversion-utils.h"
+
+// ICU PATCH: Wrap in ICU namespace
+U_NAMESPACE_BEGIN
+
+namespace double_conversion {
+
+Bignum::Chunk& Bignum::RawBigit(const int index) {
+ DOUBLE_CONVERSION_ASSERT(static_cast<unsigned>(index) < kBigitCapacity);
+ return bigits_buffer_[index];
+}
+
+
+const Bignum::Chunk& Bignum::RawBigit(const int index) const {
+ DOUBLE_CONVERSION_ASSERT(static_cast<unsigned>(index) < kBigitCapacity);
+ return bigits_buffer_[index];
+}
+
+
+template<typename S>
+static int BitSize(const S value) {
+ (void) value; // Mark variable as used.
+ return 8 * sizeof(value);
+}
+
+// Guaranteed to lie in one Bigit.
+void Bignum::AssignUInt16(const uint16_t value) {
+ DOUBLE_CONVERSION_ASSERT(kBigitSize >= BitSize(value));
+ Zero();
+ if (value > 0) {
+ RawBigit(0) = value;
+ used_bigits_ = 1;
+ }
+}
+
+
+void Bignum::AssignUInt64(uint64_t value) {
+ Zero();
+ for(int i = 0; value > 0; ++i) {
+ RawBigit(i) = value & kBigitMask;
+ value >>= kBigitSize;
+ ++used_bigits_;
+ }
+}
+
+
+void Bignum::AssignBignum(const Bignum& other) {
+ exponent_ = other.exponent_;
+ for (int i = 0; i < other.used_bigits_; ++i) {
+ RawBigit(i) = other.RawBigit(i);
+ }
+ used_bigits_ = other.used_bigits_;
+}
+
+
+static uint64_t ReadUInt64(const Vector<const char> buffer,
+ const int from,
+ const int digits_to_read) {
+ uint64_t result = 0;
+ for (int i = from; i < from + digits_to_read; ++i) {
+ const int digit = buffer[i] - '0';
+ DOUBLE_CONVERSION_ASSERT(0 <= digit && digit <= 9);
+ result = result * 10 + digit;
+ }
+ return result;
+}
+
+
+void Bignum::AssignDecimalString(const Vector<const char> value) {
+ // 2^64 = 18446744073709551616 > 10^19
+ static const int kMaxUint64DecimalDigits = 19;
+ Zero();
+ int length = value.length();
+ unsigned pos = 0;
+ // Let's just say that each digit needs 4 bits.
+ while (length >= kMaxUint64DecimalDigits) {
+ const uint64_t digits = ReadUInt64(value, pos, kMaxUint64DecimalDigits);
+ pos += kMaxUint64DecimalDigits;
+ length -= kMaxUint64DecimalDigits;
+ MultiplyByPowerOfTen(kMaxUint64DecimalDigits);
+ AddUInt64(digits);
+ }
+ const uint64_t digits = ReadUInt64(value, pos, length);
+ MultiplyByPowerOfTen(length);
+ AddUInt64(digits);
+ Clamp();
+}
+
+
+static uint64_t HexCharValue(const int c) {
+ if ('0' <= c && c <= '9') {
+ return c - '0';
+ }
+ if ('a' <= c && c <= 'f') {
+ return 10 + c - 'a';
+ }
+ DOUBLE_CONVERSION_ASSERT('A' <= c && c <= 'F');
+ return 10 + c - 'A';
+}
+
+
+// Unlike AssignDecimalString(), this function is "only" used
+// for unit-tests and therefore not performance critical.
+void Bignum::AssignHexString(Vector<const char> value) {
+ Zero();
+ // Required capacity could be reduced by ignoring leading zeros.
+ EnsureCapacity(((value.length() * 4) + kBigitSize - 1) / kBigitSize);
+ DOUBLE_CONVERSION_ASSERT(sizeof(uint64_t) * 8 >= kBigitSize + 4); // TODO: static_assert
+ // Accumulates converted hex digits until at least kBigitSize bits.
+ // Works with non-factor-of-four kBigitSizes.
+ uint64_t tmp = 0; // Accumulates converted hex digits until at least
+ for (int cnt = 0; !value.is_empty(); value.pop_back()) {
+ tmp |= (HexCharValue(value.last()) << cnt);
+ if ((cnt += 4) >= kBigitSize) {
+ RawBigit(used_bigits_++) = (tmp & kBigitMask);
+ cnt -= kBigitSize;
+ tmp >>= kBigitSize;
+ }
+ }
+ if (tmp > 0) {
+ RawBigit(used_bigits_++) = tmp;
+ }
+ Clamp();
+}
+
+
+void Bignum::AddUInt64(const uint64_t operand) {
+ if (operand == 0) {
+ return;
+ }
+ Bignum other;
+ other.AssignUInt64(operand);
+ AddBignum(other);
+}
+
+
+void Bignum::AddBignum(const Bignum& other) {
+ DOUBLE_CONVERSION_ASSERT(IsClamped());
+ DOUBLE_CONVERSION_ASSERT(other.IsClamped());
+
+ // If this has a greater exponent than other append zero-bigits to this.
+ // After this call exponent_ <= other.exponent_.
+ Align(other);
+
+ // There are two possibilities:
+ // aaaaaaaaaaa 0000 (where the 0s represent a's exponent)
+ // bbbbb 00000000
+ // ----------------
+ // ccccccccccc 0000
+ // or
+ // aaaaaaaaaa 0000
+ // bbbbbbbbb 0000000
+ // -----------------
+ // cccccccccccc 0000
+ // In both cases we might need a carry bigit.
+
+ EnsureCapacity(1 + (std::max)(BigitLength(), other.BigitLength()) - exponent_);
+ Chunk carry = 0;
+ int bigit_pos = other.exponent_ - exponent_;
+ DOUBLE_CONVERSION_ASSERT(bigit_pos >= 0);
+ for (int i = used_bigits_; i < bigit_pos; ++i) {
+ RawBigit(i) = 0;
+ }
+ for (int i = 0; i < other.used_bigits_; ++i) {
+ const Chunk my = (bigit_pos < used_bigits_) ? RawBigit(bigit_pos) : 0;
+ const Chunk sum = my + other.RawBigit(i) + carry;
+ RawBigit(bigit_pos) = sum & kBigitMask;
+ carry = sum >> kBigitSize;
+ ++bigit_pos;
+ }
+ while (carry != 0) {
+ const Chunk my = (bigit_pos < used_bigits_) ? RawBigit(bigit_pos) : 0;
+ const Chunk sum = my + carry;
+ RawBigit(bigit_pos) = sum & kBigitMask;
+ carry = sum >> kBigitSize;
+ ++bigit_pos;
+ }
+ used_bigits_ = (std::max)(bigit_pos, static_cast<int>(used_bigits_));
+ DOUBLE_CONVERSION_ASSERT(IsClamped());
+}
+
+
+void Bignum::SubtractBignum(const Bignum& other) {
+ DOUBLE_CONVERSION_ASSERT(IsClamped());
+ DOUBLE_CONVERSION_ASSERT(other.IsClamped());
+ // We require this to be bigger than other.
+ DOUBLE_CONVERSION_ASSERT(LessEqual(other, *this));
+
+ Align(other);
+
+ const int offset = other.exponent_ - exponent_;
+ Chunk borrow = 0;
+ int i;
+ for (i = 0; i < other.used_bigits_; ++i) {
+ DOUBLE_CONVERSION_ASSERT((borrow == 0) || (borrow == 1));
+ const Chunk difference = RawBigit(i + offset) - other.RawBigit(i) - borrow;
+ RawBigit(i + offset) = difference & kBigitMask;
+ borrow = difference >> (kChunkSize - 1);
+ }
+ while (borrow != 0) {
+ const Chunk difference = RawBigit(i + offset) - borrow;
+ RawBigit(i + offset) = difference & kBigitMask;
+ borrow = difference >> (kChunkSize - 1);
+ ++i;
+ }
+ Clamp();
+}
+
+
+void Bignum::ShiftLeft(const int shift_amount) {
+ if (used_bigits_ == 0) {
+ return;
+ }
+ exponent_ += (shift_amount / kBigitSize);
+ const int local_shift = shift_amount % kBigitSize;
+ EnsureCapacity(used_bigits_ + 1);
+ BigitsShiftLeft(local_shift);
+}
+
+
+void Bignum::MultiplyByUInt32(const uint32_t factor) {
+ if (factor == 1) {
+ return;
+ }
+ if (factor == 0) {
+ Zero();
+ return;
+ }
+ if (used_bigits_ == 0) {
+ return;
+ }
+ // The product of a bigit with the factor is of size kBigitSize + 32.
+ // Assert that this number + 1 (for the carry) fits into double chunk.
+ DOUBLE_CONVERSION_ASSERT(kDoubleChunkSize >= kBigitSize + 32 + 1);
+ DoubleChunk carry = 0;
+ for (int i = 0; i < used_bigits_; ++i) {
+ const DoubleChunk product = static_cast<DoubleChunk>(factor) * RawBigit(i) + carry;
+ RawBigit(i) = static_cast<Chunk>(product & kBigitMask);
+ carry = (product >> kBigitSize);
+ }
+ while (carry != 0) {
+ EnsureCapacity(used_bigits_ + 1);
+ RawBigit(used_bigits_) = carry & kBigitMask;
+ used_bigits_++;
+ carry >>= kBigitSize;
+ }
+}
+
+
+void Bignum::MultiplyByUInt64(const uint64_t factor) {
+ if (factor == 1) {
+ return;
+ }
+ if (factor == 0) {
+ Zero();
+ return;
+ }
+ if (used_bigits_ == 0) {
+ return;
+ }
+ DOUBLE_CONVERSION_ASSERT(kBigitSize < 32);
+ uint64_t carry = 0;
+ const uint64_t low = factor & 0xFFFFFFFF;
+ const uint64_t high = factor >> 32;
+ for (int i = 0; i < used_bigits_; ++i) {
+ const uint64_t product_low = low * RawBigit(i);
+ const uint64_t product_high = high * RawBigit(i);
+ const uint64_t tmp = (carry & kBigitMask) + product_low;
+ RawBigit(i) = tmp & kBigitMask;
+ carry = (carry >> kBigitSize) + (tmp >> kBigitSize) +
+ (product_high << (32 - kBigitSize));
+ }
+ while (carry != 0) {
+ EnsureCapacity(used_bigits_ + 1);
+ RawBigit(used_bigits_) = carry & kBigitMask;
+ used_bigits_++;
+ carry >>= kBigitSize;
+ }
+}
+
+
+void Bignum::MultiplyByPowerOfTen(const int exponent) {
+ static const uint64_t kFive27 = DOUBLE_CONVERSION_UINT64_2PART_C(0x6765c793, fa10079d);
+ static const uint16_t kFive1 = 5;
+ static const uint16_t kFive2 = kFive1 * 5;
+ static const uint16_t kFive3 = kFive2 * 5;
+ static const uint16_t kFive4 = kFive3 * 5;
+ static const uint16_t kFive5 = kFive4 * 5;
+ static const uint16_t kFive6 = kFive5 * 5;
+ static const uint32_t kFive7 = kFive6 * 5;
+ static const uint32_t kFive8 = kFive7 * 5;
+ static const uint32_t kFive9 = kFive8 * 5;
+ static const uint32_t kFive10 = kFive9 * 5;
+ static const uint32_t kFive11 = kFive10 * 5;
+ static const uint32_t kFive12 = kFive11 * 5;
+ static const uint32_t kFive13 = kFive12 * 5;
+ static const uint32_t kFive1_to_12[] =
+ { kFive1, kFive2, kFive3, kFive4, kFive5, kFive6,
+ kFive7, kFive8, kFive9, kFive10, kFive11, kFive12 };
+
+ DOUBLE_CONVERSION_ASSERT(exponent >= 0);
+
+ if (exponent == 0) {
+ return;
+ }
+ if (used_bigits_ == 0) {
+ return;
+ }
+ // We shift by exponent at the end just before returning.
+ int remaining_exponent = exponent;
+ while (remaining_exponent >= 27) {
+ MultiplyByUInt64(kFive27);
+ remaining_exponent -= 27;
+ }
+ while (remaining_exponent >= 13) {
+ MultiplyByUInt32(kFive13);
+ remaining_exponent -= 13;
+ }
+ if (remaining_exponent > 0) {
+ MultiplyByUInt32(kFive1_to_12[remaining_exponent - 1]);
+ }
+ ShiftLeft(exponent);
+}
+
+
+void Bignum::Square() {
+ DOUBLE_CONVERSION_ASSERT(IsClamped());
+ const int product_length = 2 * used_bigits_;
+ EnsureCapacity(product_length);
+
+ // Comba multiplication: compute each column separately.
+ // Example: r = a2a1a0 * b2b1b0.
+ // r = 1 * a0b0 +
+ // 10 * (a1b0 + a0b1) +
+ // 100 * (a2b0 + a1b1 + a0b2) +
+ // 1000 * (a2b1 + a1b2) +
+ // 10000 * a2b2
+ //
+ // In the worst case we have to accumulate nb-digits products of digit*digit.
+ //
+ // Assert that the additional number of bits in a DoubleChunk are enough to
+ // sum up used_digits of Bigit*Bigit.
+ if ((1 << (2 * (kChunkSize - kBigitSize))) <= used_bigits_) {
+ DOUBLE_CONVERSION_UNIMPLEMENTED();
+ }
+ DoubleChunk accumulator = 0;
+ // First shift the digits so we don't overwrite them.
+ const int copy_offset = used_bigits_;
+ for (int i = 0; i < used_bigits_; ++i) {
+ RawBigit(copy_offset + i) = RawBigit(i);
+ }
+ // We have two loops to avoid some 'if's in the loop.
+ for (int i = 0; i < used_bigits_; ++i) {
+ // Process temporary digit i with power i.
+ // The sum of the two indices must be equal to i.
+ int bigit_index1 = i;
+ int bigit_index2 = 0;
+ // Sum all of the sub-products.
+ while (bigit_index1 >= 0) {
+ const Chunk chunk1 = RawBigit(copy_offset + bigit_index1);
+ const Chunk chunk2 = RawBigit(copy_offset + bigit_index2);
+ accumulator += static_cast<DoubleChunk>(chunk1) * chunk2;
+ bigit_index1--;
+ bigit_index2++;
+ }
+ RawBigit(i) = static_cast<Chunk>(accumulator) & kBigitMask;
+ accumulator >>= kBigitSize;
+ }
+ for (int i = used_bigits_; i < product_length; ++i) {
+ int bigit_index1 = used_bigits_ - 1;
+ int bigit_index2 = i - bigit_index1;
+ // Invariant: sum of both indices is again equal to i.
+ // Inner loop runs 0 times on last iteration, emptying accumulator.
+ while (bigit_index2 < used_bigits_) {
+ const Chunk chunk1 = RawBigit(copy_offset + bigit_index1);
+ const Chunk chunk2 = RawBigit(copy_offset + bigit_index2);
+ accumulator += static_cast<DoubleChunk>(chunk1) * chunk2;
+ bigit_index1--;
+ bigit_index2++;
+ }
+ // The overwritten RawBigit(i) will never be read in further loop iterations,
+ // because bigit_index1 and bigit_index2 are always greater
+ // than i - used_bigits_.
+ RawBigit(i) = static_cast<Chunk>(accumulator) & kBigitMask;
+ accumulator >>= kBigitSize;
+ }
+ // Since the result was guaranteed to lie inside the number the
+ // accumulator must be 0 now.
+ DOUBLE_CONVERSION_ASSERT(accumulator == 0);
+
+ // Don't forget to update the used_digits and the exponent.
+ used_bigits_ = product_length;
+ exponent_ *= 2;
+ Clamp();
+}
+
+
+void Bignum::AssignPowerUInt16(uint16_t base, const int power_exponent) {
+ DOUBLE_CONVERSION_ASSERT(base != 0);
+ DOUBLE_CONVERSION_ASSERT(power_exponent >= 0);
+ if (power_exponent == 0) {
+ AssignUInt16(1);
+ return;
+ }
+ Zero();
+ int shifts = 0;
+ // We expect base to be in range 2-32, and most often to be 10.
+ // It does not make much sense to implement different algorithms for counting
+ // the bits.
+ while ((base & 1) == 0) {
+ base >>= 1;
+ shifts++;
+ }
+ int bit_size = 0;
+ int tmp_base = base;
+ while (tmp_base != 0) {
+ tmp_base >>= 1;
+ bit_size++;
+ }
+ const int final_size = bit_size * power_exponent;
+ // 1 extra bigit for the shifting, and one for rounded final_size.
+ EnsureCapacity(final_size / kBigitSize + 2);
+
+ // Left to Right exponentiation.
+ int mask = 1;
+ while (power_exponent >= mask) mask <<= 1;
+
+ // The mask is now pointing to the bit above the most significant 1-bit of
+ // power_exponent.
+ // Get rid of first 1-bit;
+ mask >>= 2;
+ uint64_t this_value = base;
+
+ bool delayed_multiplication = false;
+ const uint64_t max_32bits = 0xFFFFFFFF;
+ while (mask != 0 && this_value <= max_32bits) {
+ this_value = this_value * this_value;
+ // Verify that there is enough space in this_value to perform the
+ // multiplication. The first bit_size bits must be 0.
+ if ((power_exponent & mask) != 0) {
+ DOUBLE_CONVERSION_ASSERT(bit_size > 0);
+ const uint64_t base_bits_mask =
+ ~((static_cast<uint64_t>(1) << (64 - bit_size)) - 1);
+ const bool high_bits_zero = (this_value & base_bits_mask) == 0;
+ if (high_bits_zero) {
+ this_value *= base;
+ } else {
+ delayed_multiplication = true;
+ }
+ }
+ mask >>= 1;
+ }
+ AssignUInt64(this_value);
+ if (delayed_multiplication) {
+ MultiplyByUInt32(base);
+ }
+
+ // Now do the same thing as a bignum.
+ while (mask != 0) {
+ Square();
+ if ((power_exponent & mask) != 0) {
+ MultiplyByUInt32(base);
+ }
+ mask >>= 1;
+ }
+
+ // And finally add the saved shifts.
+ ShiftLeft(shifts * power_exponent);
+}
+
+
+// Precondition: this/other < 16bit.
+uint16_t Bignum::DivideModuloIntBignum(const Bignum& other) {
+ DOUBLE_CONVERSION_ASSERT(IsClamped());
+ DOUBLE_CONVERSION_ASSERT(other.IsClamped());
+ DOUBLE_CONVERSION_ASSERT(other.used_bigits_ > 0);
+
+ // Easy case: if we have less digits than the divisor than the result is 0.
+ // Note: this handles the case where this == 0, too.
+ if (BigitLength() < other.BigitLength()) {
+ return 0;
+ }
+
+ Align(other);
+
+ uint16_t result = 0;
+
+ // Start by removing multiples of 'other' until both numbers have the same
+ // number of digits.
+ while (BigitLength() > other.BigitLength()) {
+ // This naive approach is extremely inefficient if `this` divided by other
+ // is big. This function is implemented for doubleToString where
+ // the result should be small (less than 10).
+ DOUBLE_CONVERSION_ASSERT(other.RawBigit(other.used_bigits_ - 1) >= ((1 << kBigitSize) / 16));
+ DOUBLE_CONVERSION_ASSERT(RawBigit(used_bigits_ - 1) < 0x10000);
+ // Remove the multiples of the first digit.
+ // Example this = 23 and other equals 9. -> Remove 2 multiples.
+ result += static_cast<uint16_t>(RawBigit(used_bigits_ - 1));
+ SubtractTimes(other, RawBigit(used_bigits_ - 1));
+ }
+
+ DOUBLE_CONVERSION_ASSERT(BigitLength() == other.BigitLength());
+
+ // Both bignums are at the same length now.
+ // Since other has more than 0 digits we know that the access to
+ // RawBigit(used_bigits_ - 1) is safe.
+ const Chunk this_bigit = RawBigit(used_bigits_ - 1);
+ const Chunk other_bigit = other.RawBigit(other.used_bigits_ - 1);
+
+ if (other.used_bigits_ == 1) {
+ // Shortcut for easy (and common) case.
+ int quotient = this_bigit / other_bigit;
+ RawBigit(used_bigits_ - 1) = this_bigit - other_bigit * quotient;
+ DOUBLE_CONVERSION_ASSERT(quotient < 0x10000);
+ result += static_cast<uint16_t>(quotient);
+ Clamp();
+ return result;
+ }
+
+ const int division_estimate = this_bigit / (other_bigit + 1);
+ DOUBLE_CONVERSION_ASSERT(division_estimate < 0x10000);
+ result += static_cast<uint16_t>(division_estimate);
+ SubtractTimes(other, division_estimate);
+
+ if (other_bigit * (division_estimate + 1) > this_bigit) {
+ // No need to even try to subtract. Even if other's remaining digits were 0
+ // another subtraction would be too much.
+ return result;
+ }
+
+ while (LessEqual(other, *this)) {
+ SubtractBignum(other);
+ result++;
+ }
+ return result;
+}
+
+
+template<typename S>
+static int SizeInHexChars(S number) {
+ DOUBLE_CONVERSION_ASSERT(number > 0);
+ int result = 0;
+ while (number != 0) {
+ number >>= 4;
+ result++;
+ }
+ return result;
+}
+
+
+static char HexCharOfValue(const int value) {
+ DOUBLE_CONVERSION_ASSERT(0 <= value && value <= 16);
+ if (value < 10) {
+ return static_cast<char>(value + '0');
+ }
+ return static_cast<char>(value - 10 + 'A');
+}
+
+
+bool Bignum::ToHexString(char* buffer, const int buffer_size) const {
+ DOUBLE_CONVERSION_ASSERT(IsClamped());
+ // Each bigit must be printable as separate hex-character.
+ DOUBLE_CONVERSION_ASSERT(kBigitSize % 4 == 0);
+ static const int kHexCharsPerBigit = kBigitSize / 4;
+
+ if (used_bigits_ == 0) {
+ if (buffer_size < 2) {
+ return false;
+ }
+ buffer[0] = '0';
+ buffer[1] = '\0';
+ return true;
+ }
+ // We add 1 for the terminating '\0' character.
+ const int needed_chars = (BigitLength() - 1) * kHexCharsPerBigit +
+ SizeInHexChars(RawBigit(used_bigits_ - 1)) + 1;
+ if (needed_chars > buffer_size) {
+ return false;
+ }
+ int string_index = needed_chars - 1;
+ buffer[string_index--] = '\0';
+ for (int i = 0; i < exponent_; ++i) {
+ for (int j = 0; j < kHexCharsPerBigit; ++j) {
+ buffer[string_index--] = '0';
+ }
+ }
+ for (int i = 0; i < used_bigits_ - 1; ++i) {
+ Chunk current_bigit = RawBigit(i);
+ for (int j = 0; j < kHexCharsPerBigit; ++j) {
+ buffer[string_index--] = HexCharOfValue(current_bigit & 0xF);
+ current_bigit >>= 4;
+ }
+ }
+ // And finally the last bigit.
+ Chunk most_significant_bigit = RawBigit(used_bigits_ - 1);
+ while (most_significant_bigit != 0) {
+ buffer[string_index--] = HexCharOfValue(most_significant_bigit & 0xF);
+ most_significant_bigit >>= 4;
+ }
+ return true;
+}
+
+
+Bignum::Chunk Bignum::BigitOrZero(const int index) const {
+ if (index >= BigitLength()) {
+ return 0;
+ }
+ if (index < exponent_) {
+ return 0;
+ }
+ return RawBigit(index - exponent_);
+}
+
+
+int Bignum::Compare(const Bignum& a, const Bignum& b) {
+ DOUBLE_CONVERSION_ASSERT(a.IsClamped());
+ DOUBLE_CONVERSION_ASSERT(b.IsClamped());
+ const int bigit_length_a = a.BigitLength();
+ const int bigit_length_b = b.BigitLength();
+ if (bigit_length_a < bigit_length_b) {
+ return -1;
+ }
+ if (bigit_length_a > bigit_length_b) {
+ return +1;
+ }
+ for (int i = bigit_length_a - 1; i >= (std::min)(a.exponent_, b.exponent_); --i) {
+ const Chunk bigit_a = a.BigitOrZero(i);
+ const Chunk bigit_b = b.BigitOrZero(i);
+ if (bigit_a < bigit_b) {
+ return -1;
+ }
+ if (bigit_a > bigit_b) {
+ return +1;
+ }
+ // Otherwise they are equal up to this digit. Try the next digit.
+ }
+ return 0;
+}
+
+
+int Bignum::PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c) {
+ DOUBLE_CONVERSION_ASSERT(a.IsClamped());
+ DOUBLE_CONVERSION_ASSERT(b.IsClamped());
+ DOUBLE_CONVERSION_ASSERT(c.IsClamped());
+ if (a.BigitLength() < b.BigitLength()) {
+ return PlusCompare(b, a, c);
+ }
+ if (a.BigitLength() + 1 < c.BigitLength()) {
+ return -1;
+ }
+ if (a.BigitLength() > c.BigitLength()) {
+ return +1;
+ }
+ // The exponent encodes 0-bigits. So if there are more 0-digits in 'a' than
+ // 'b' has digits, then the bigit-length of 'a'+'b' must be equal to the one
+ // of 'a'.
+ if (a.exponent_ >= b.BigitLength() && a.BigitLength() < c.BigitLength()) {
+ return -1;
+ }
+
+ Chunk borrow = 0;
+ // Starting at min_exponent all digits are == 0. So no need to compare them.
+ const int min_exponent = (std::min)((std::min)(a.exponent_, b.exponent_), c.exponent_);
+ for (int i = c.BigitLength() - 1; i >= min_exponent; --i) {
+ const Chunk chunk_a = a.BigitOrZero(i);
+ const Chunk chunk_b = b.BigitOrZero(i);
+ const Chunk chunk_c = c.BigitOrZero(i);
+ const Chunk sum = chunk_a + chunk_b;
+ if (sum > chunk_c + borrow) {
+ return +1;
+ } else {
+ borrow = chunk_c + borrow - sum;
+ if (borrow > 1) {
+ return -1;
+ }
+ borrow <<= kBigitSize;
+ }
+ }
+ if (borrow == 0) {
+ return 0;
+ }
+ return -1;
+}
+
+
+void Bignum::Clamp() {
+ while (used_bigits_ > 0 && RawBigit(used_bigits_ - 1) == 0) {
+ used_bigits_--;
+ }
+ if (used_bigits_ == 0) {
+ // Zero.
+ exponent_ = 0;
+ }
+}
+
+
+void Bignum::Align(const Bignum& other) {
+ if (exponent_ > other.exponent_) {
+ // If "X" represents a "hidden" bigit (by the exponent) then we are in the
+ // following case (a == this, b == other):
+ // a: aaaaaaXXXX or a: aaaaaXXX
+ // b: bbbbbbX b: bbbbbbbbXX
+ // We replace some of the hidden digits (X) of a with 0 digits.
+ // a: aaaaaa000X or a: aaaaa0XX
+ const int zero_bigits = exponent_ - other.exponent_;
+ EnsureCapacity(used_bigits_ + zero_bigits);
+ for (int i = used_bigits_ - 1; i >= 0; --i) {
+ RawBigit(i + zero_bigits) = RawBigit(i);
+ }
+ for (int i = 0; i < zero_bigits; ++i) {
+ RawBigit(i) = 0;
+ }
+ used_bigits_ += zero_bigits;
+ exponent_ -= zero_bigits;
+
+ DOUBLE_CONVERSION_ASSERT(used_bigits_ >= 0);
+ DOUBLE_CONVERSION_ASSERT(exponent_ >= 0);
+ }
+}
+
+
+void Bignum::BigitsShiftLeft(const int shift_amount) {
+ DOUBLE_CONVERSION_ASSERT(shift_amount < kBigitSize);
+ DOUBLE_CONVERSION_ASSERT(shift_amount >= 0);
+ Chunk carry = 0;
+ for (int i = 0; i < used_bigits_; ++i) {
+ const Chunk new_carry = RawBigit(i) >> (kBigitSize - shift_amount);
+ RawBigit(i) = ((RawBigit(i) << shift_amount) + carry) & kBigitMask;
+ carry = new_carry;
+ }
+ if (carry != 0) {
+ RawBigit(used_bigits_) = carry;
+ used_bigits_++;
+ }
+}
+
+
+void Bignum::SubtractTimes(const Bignum& other, const int factor) {
+ DOUBLE_CONVERSION_ASSERT(exponent_ <= other.exponent_);
+ if (factor < 3) {
+ for (int i = 0; i < factor; ++i) {
+ SubtractBignum(other);
+ }
+ return;
+ }
+ Chunk borrow = 0;
+ const int exponent_diff = other.exponent_ - exponent_;
+ for (int i = 0; i < other.used_bigits_; ++i) {
+ const DoubleChunk product = static_cast<DoubleChunk>(factor) * other.RawBigit(i);
+ const DoubleChunk remove = borrow + product;
+ const Chunk difference = RawBigit(i + exponent_diff) - (remove & kBigitMask);
+ RawBigit(i + exponent_diff) = difference & kBigitMask;
+ borrow = static_cast<Chunk>((difference >> (kChunkSize - 1)) +
+ (remove >> kBigitSize));
+ }
+ for (int i = other.used_bigits_ + exponent_diff; i < used_bigits_; ++i) {
+ if (borrow == 0) {
+ return;
+ }
+ const Chunk difference = RawBigit(i) - borrow;
+ RawBigit(i) = difference & kBigitMask;
+ borrow = difference >> (kChunkSize - 1);
+ }
+ Clamp();
+}
+
+
+} // namespace double_conversion
+
+// ICU PATCH: Close ICU namespace
+U_NAMESPACE_END
+#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
diff --git a/contrib/libs/icu/i18n/double-conversion-bignum.h b/contrib/libs/icu/i18n/double-conversion-bignum.h
index bae900a15a..a8617d26f5 100644
--- a/contrib/libs/icu/i18n/double-conversion-bignum.h
+++ b/contrib/libs/icu/i18n/double-conversion-bignum.h
@@ -1,170 +1,170 @@
-// © 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_BIGNUM_H_
-#define DOUBLE_CONVERSION_BIGNUM_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 {
-
-class Bignum {
- public:
- // 3584 = 128 * 28. We can represent 2^3584 > 10^1000 accurately.
- // This bignum can encode much bigger numbers, since it contains an
- // exponent.
- static const int kMaxSignificantBits = 3584;
-
- Bignum() : used_bigits_(0), exponent_(0) {}
-
- void AssignUInt16(const uint16_t value);
- void AssignUInt64(uint64_t value);
- void AssignBignum(const Bignum& other);
-
- void AssignDecimalString(const Vector<const char> value);
- void AssignHexString(const Vector<const char> value);
-
- void AssignPowerUInt16(uint16_t base, const int exponent);
-
- void AddUInt64(const uint64_t operand);
- void AddBignum(const Bignum& other);
- // Precondition: this >= other.
- void SubtractBignum(const Bignum& other);
-
- void Square();
- void ShiftLeft(const int shift_amount);
- void MultiplyByUInt32(const uint32_t factor);
- void MultiplyByUInt64(const uint64_t factor);
- void MultiplyByPowerOfTen(const int exponent);
- void Times10() { return MultiplyByUInt32(10); }
- // Pseudocode:
- // int result = this / other;
- // this = this % other;
- // In the worst case this function is in O(this/other).
- uint16_t DivideModuloIntBignum(const Bignum& other);
-
- bool ToHexString(char* buffer, const int buffer_size) const;
-
- // Returns
- // -1 if a < b,
- // 0 if a == b, and
- // +1 if a > b.
- static int Compare(const Bignum& a, const Bignum& b);
- static bool Equal(const Bignum& a, const Bignum& b) {
- return Compare(a, b) == 0;
- }
- static bool LessEqual(const Bignum& a, const Bignum& b) {
- return Compare(a, b) <= 0;
- }
- static bool Less(const Bignum& a, const Bignum& b) {
- return Compare(a, b) < 0;
- }
- // Returns Compare(a + b, c);
- static int PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c);
- // Returns a + b == c
- static bool PlusEqual(const Bignum& a, const Bignum& b, const Bignum& c) {
- return PlusCompare(a, b, c) == 0;
- }
- // Returns a + b <= c
- static bool PlusLessEqual(const Bignum& a, const Bignum& b, const Bignum& c) {
- return PlusCompare(a, b, c) <= 0;
- }
- // Returns a + b < c
- static bool PlusLess(const Bignum& a, const Bignum& b, const Bignum& c) {
- return PlusCompare(a, b, c) < 0;
- }
- private:
- typedef uint32_t Chunk;
- typedef uint64_t DoubleChunk;
-
- static const int kChunkSize = sizeof(Chunk) * 8;
- static const int kDoubleChunkSize = sizeof(DoubleChunk) * 8;
- // With bigit size of 28 we loose some bits, but a double still fits easily
- // into two chunks, and more importantly we can use the Comba multiplication.
- static const int kBigitSize = 28;
- static const Chunk kBigitMask = (1 << kBigitSize) - 1;
- // Every instance allocates kBigitLength chunks on the stack. Bignums cannot
- // grow. There are no checks if the stack-allocated space is sufficient.
- static const int kBigitCapacity = kMaxSignificantBits / kBigitSize;
-
- static void EnsureCapacity(const int size) {
- if (size > kBigitCapacity) {
- DOUBLE_CONVERSION_UNREACHABLE();
- }
- }
- void Align(const Bignum& other);
- void Clamp();
- bool IsClamped() const {
- return used_bigits_ == 0 || RawBigit(used_bigits_ - 1) != 0;
- }
- void Zero() {
- used_bigits_ = 0;
- exponent_ = 0;
- }
- // Requires this to have enough capacity (no tests done).
- // Updates used_bigits_ if necessary.
- // shift_amount must be < kBigitSize.
- void BigitsShiftLeft(const int shift_amount);
- // BigitLength includes the "hidden" bigits encoded in the exponent.
- int BigitLength() const { return used_bigits_ + exponent_; }
- Chunk& RawBigit(const int index);
- const Chunk& RawBigit(const int index) const;
- Chunk BigitOrZero(const int index) const;
- void SubtractTimes(const Bignum& other, const int factor);
-
- // The Bignum's value is value(bigits_buffer_) * 2^(exponent_ * kBigitSize),
- // where the value of the buffer consists of the lower kBigitSize bits of
- // the first used_bigits_ Chunks in bigits_buffer_, first chunk has lowest
- // significant bits.
- int16_t used_bigits_;
- int16_t exponent_;
- Chunk bigits_buffer_[kBigitCapacity];
-
- DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN(Bignum);
-};
-
-} // namespace double_conversion
-
-// ICU PATCH: Close ICU namespace
-U_NAMESPACE_END
-
-#endif // DOUBLE_CONVERSION_BIGNUM_H_
-#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
+// © 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_BIGNUM_H_
+#define DOUBLE_CONVERSION_BIGNUM_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 {
+
+class Bignum {
+ public:
+ // 3584 = 128 * 28. We can represent 2^3584 > 10^1000 accurately.
+ // This bignum can encode much bigger numbers, since it contains an
+ // exponent.
+ static const int kMaxSignificantBits = 3584;
+
+ Bignum() : used_bigits_(0), exponent_(0) {}
+
+ void AssignUInt16(const uint16_t value);
+ void AssignUInt64(uint64_t value);
+ void AssignBignum(const Bignum& other);
+
+ void AssignDecimalString(const Vector<const char> value);
+ void AssignHexString(const Vector<const char> value);
+
+ void AssignPowerUInt16(uint16_t base, const int exponent);
+
+ void AddUInt64(const uint64_t operand);
+ void AddBignum(const Bignum& other);
+ // Precondition: this >= other.
+ void SubtractBignum(const Bignum& other);
+
+ void Square();
+ void ShiftLeft(const int shift_amount);
+ void MultiplyByUInt32(const uint32_t factor);
+ void MultiplyByUInt64(const uint64_t factor);
+ void MultiplyByPowerOfTen(const int exponent);
+ void Times10() { return MultiplyByUInt32(10); }
+ // Pseudocode:
+ // int result = this / other;
+ // this = this % other;
+ // In the worst case this function is in O(this/other).
+ uint16_t DivideModuloIntBignum(const Bignum& other);
+
+ bool ToHexString(char* buffer, const int buffer_size) const;
+
+ // Returns
+ // -1 if a < b,
+ // 0 if a == b, and
+ // +1 if a > b.
+ static int Compare(const Bignum& a, const Bignum& b);
+ static bool Equal(const Bignum& a, const Bignum& b) {
+ return Compare(a, b) == 0;
+ }
+ static bool LessEqual(const Bignum& a, const Bignum& b) {
+ return Compare(a, b) <= 0;
+ }
+ static bool Less(const Bignum& a, const Bignum& b) {
+ return Compare(a, b) < 0;
+ }
+ // Returns Compare(a + b, c);
+ static int PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c);
+ // Returns a + b == c
+ static bool PlusEqual(const Bignum& a, const Bignum& b, const Bignum& c) {
+ return PlusCompare(a, b, c) == 0;
+ }
+ // Returns a + b <= c
+ static bool PlusLessEqual(const Bignum& a, const Bignum& b, const Bignum& c) {
+ return PlusCompare(a, b, c) <= 0;
+ }
+ // Returns a + b < c
+ static bool PlusLess(const Bignum& a, const Bignum& b, const Bignum& c) {
+ return PlusCompare(a, b, c) < 0;
+ }
+ private:
+ typedef uint32_t Chunk;
+ typedef uint64_t DoubleChunk;
+
+ static const int kChunkSize = sizeof(Chunk) * 8;
+ static const int kDoubleChunkSize = sizeof(DoubleChunk) * 8;
+ // With bigit size of 28 we loose some bits, but a double still fits easily
+ // into two chunks, and more importantly we can use the Comba multiplication.
+ static const int kBigitSize = 28;
+ static const Chunk kBigitMask = (1 << kBigitSize) - 1;
+ // Every instance allocates kBigitLength chunks on the stack. Bignums cannot
+ // grow. There are no checks if the stack-allocated space is sufficient.
+ static const int kBigitCapacity = kMaxSignificantBits / kBigitSize;
+
+ static void EnsureCapacity(const int size) {
+ if (size > kBigitCapacity) {
+ DOUBLE_CONVERSION_UNREACHABLE();
+ }
+ }
+ void Align(const Bignum& other);
+ void Clamp();
+ bool IsClamped() const {
+ return used_bigits_ == 0 || RawBigit(used_bigits_ - 1) != 0;
+ }
+ void Zero() {
+ used_bigits_ = 0;
+ exponent_ = 0;
+ }
+ // Requires this to have enough capacity (no tests done).
+ // Updates used_bigits_ if necessary.
+ // shift_amount must be < kBigitSize.
+ void BigitsShiftLeft(const int shift_amount);
+ // BigitLength includes the "hidden" bigits encoded in the exponent.
+ int BigitLength() const { return used_bigits_ + exponent_; }
+ Chunk& RawBigit(const int index);
+ const Chunk& RawBigit(const int index) const;
+ Chunk BigitOrZero(const int index) const;
+ void SubtractTimes(const Bignum& other, const int factor);
+
+ // The Bignum's value is value(bigits_buffer_) * 2^(exponent_ * kBigitSize),
+ // where the value of the buffer consists of the lower kBigitSize bits of
+ // the first used_bigits_ Chunks in bigits_buffer_, first chunk has lowest
+ // significant bits.
+ int16_t used_bigits_;
+ int16_t exponent_;
+ Chunk bigits_buffer_[kBigitCapacity];
+
+ DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN(Bignum);
+};
+
+} // namespace double_conversion
+
+// ICU PATCH: Close ICU namespace
+U_NAMESPACE_END
+
+#endif // DOUBLE_CONVERSION_BIGNUM_H_
+#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
diff --git a/contrib/libs/icu/i18n/double-conversion-cached-powers.cpp b/contrib/libs/icu/i18n/double-conversion-cached-powers.cpp
index 3bc35c8aaf..e0ec9e6f55 100644
--- a/contrib/libs/icu/i18n/double-conversion-cached-powers.cpp
+++ b/contrib/libs/icu/i18n/double-conversion-cached-powers.cpp
@@ -1,193 +1,193 @@
-// © 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 2006-2008 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 <climits>
-#include <cmath>
-#include <cstdarg>
-
-// ICU PATCH: Customize header file paths for ICU.
-
-#include "double-conversion-utils.h"
-
-#include "double-conversion-cached-powers.h"
-
-// ICU PATCH: Wrap in ICU namespace
-U_NAMESPACE_BEGIN
-
-namespace double_conversion {
-
-namespace PowersOfTenCache {
-
-struct CachedPower {
- uint64_t significand;
- int16_t binary_exponent;
- int16_t decimal_exponent;
-};
-
-static const CachedPower kCachedPowers[] = {
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xfa8fd5a0, 081c0288), -1220, -348},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xbaaee17f, a23ebf76), -1193, -340},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x8b16fb20, 3055ac76), -1166, -332},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xcf42894a, 5dce35ea), -1140, -324},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x9a6bb0aa, 55653b2d), -1113, -316},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xe61acf03, 3d1a45df), -1087, -308},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xab70fe17, c79ac6ca), -1060, -300},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xff77b1fc, bebcdc4f), -1034, -292},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xbe5691ef, 416bd60c), -1007, -284},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x8dd01fad, 907ffc3c), -980, -276},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xd3515c28, 31559a83), -954, -268},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x9d71ac8f, ada6c9b5), -927, -260},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xea9c2277, 23ee8bcb), -901, -252},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xaecc4991, 4078536d), -874, -244},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x823c1279, 5db6ce57), -847, -236},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xc2109436, 4dfb5637), -821, -228},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x9096ea6f, 3848984f), -794, -220},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xd77485cb, 25823ac7), -768, -212},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xa086cfcd, 97bf97f4), -741, -204},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xef340a98, 172aace5), -715, -196},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xb23867fb, 2a35b28e), -688, -188},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x84c8d4df, d2c63f3b), -661, -180},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xc5dd4427, 1ad3cdba), -635, -172},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x936b9fce, bb25c996), -608, -164},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xdbac6c24, 7d62a584), -582, -156},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xa3ab6658, 0d5fdaf6), -555, -148},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xf3e2f893, dec3f126), -529, -140},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xb5b5ada8, aaff80b8), -502, -132},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x87625f05, 6c7c4a8b), -475, -124},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xc9bcff60, 34c13053), -449, -116},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x964e858c, 91ba2655), -422, -108},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xdff97724, 70297ebd), -396, -100},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xa6dfbd9f, b8e5b88f), -369, -92},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xf8a95fcf, 88747d94), -343, -84},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xb9447093, 8fa89bcf), -316, -76},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x8a08f0f8, bf0f156b), -289, -68},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xcdb02555, 653131b6), -263, -60},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x993fe2c6, d07b7fac), -236, -52},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xe45c10c4, 2a2b3b06), -210, -44},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xaa242499, 697392d3), -183, -36},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xfd87b5f2, 8300ca0e), -157, -28},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xbce50864, 92111aeb), -130, -20},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x8cbccc09, 6f5088cc), -103, -12},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xd1b71758, e219652c), -77, -4},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x9c400000, 00000000), -50, 4},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xe8d4a510, 00000000), -24, 12},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xad78ebc5, ac620000), 3, 20},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x813f3978, f8940984), 30, 28},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xc097ce7b, c90715b3), 56, 36},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x8f7e32ce, 7bea5c70), 83, 44},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xd5d238a4, abe98068), 109, 52},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x9f4f2726, 179a2245), 136, 60},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xed63a231, d4c4fb27), 162, 68},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xb0de6538, 8cc8ada8), 189, 76},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x83c7088e, 1aab65db), 216, 84},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xc45d1df9, 42711d9a), 242, 92},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x924d692c, a61be758), 269, 100},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xda01ee64, 1a708dea), 295, 108},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xa26da399, 9aef774a), 322, 116},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xf209787b, b47d6b85), 348, 124},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xb454e4a1, 79dd1877), 375, 132},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x865b8692, 5b9bc5c2), 402, 140},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xc83553c5, c8965d3d), 428, 148},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x952ab45c, fa97a0b3), 455, 156},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xde469fbd, 99a05fe3), 481, 164},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xa59bc234, db398c25), 508, 172},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xf6c69a72, a3989f5c), 534, 180},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xb7dcbf53, 54e9bece), 561, 188},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x88fcf317, f22241e2), 588, 196},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xcc20ce9b, d35c78a5), 614, 204},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x98165af3, 7b2153df), 641, 212},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xe2a0b5dc, 971f303a), 667, 220},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xa8d9d153, 5ce3b396), 694, 228},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xfb9b7cd9, a4a7443c), 720, 236},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xbb764c4c, a7a44410), 747, 244},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x8bab8eef, b6409c1a), 774, 252},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xd01fef10, a657842c), 800, 260},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x9b10a4e5, e9913129), 827, 268},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xe7109bfb, a19c0c9d), 853, 276},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xac2820d9, 623bf429), 880, 284},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x80444b5e, 7aa7cf85), 907, 292},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xbf21e440, 03acdd2d), 933, 300},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x8e679c2f, 5e44ff8f), 960, 308},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xd433179d, 9c8cb841), 986, 316},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0x9e19db92, b4e31ba9), 1013, 324},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xeb96bf6e, badf77d9), 1039, 332},
- {DOUBLE_CONVERSION_UINT64_2PART_C(0xaf87023b, 9bf0ee6b), 1066, 340},
-};
-
-static const int kCachedPowersOffset = 348; // -1 * the first decimal_exponent.
-static const double kD_1_LOG2_10 = 0.30102999566398114; // 1 / lg(10)
-
-void GetCachedPowerForBinaryExponentRange(
- int min_exponent,
- int max_exponent,
- DiyFp* power,
- int* decimal_exponent) {
- int kQ = DiyFp::kSignificandSize;
- double k = ceil((min_exponent + kQ - 1) * kD_1_LOG2_10);
- int foo = kCachedPowersOffset;
- int index =
- (foo + static_cast<int>(k) - 1) / kDecimalExponentDistance + 1;
- DOUBLE_CONVERSION_ASSERT(0 <= index && index < static_cast<int>(DOUBLE_CONVERSION_ARRAY_SIZE(kCachedPowers)));
- CachedPower cached_power = kCachedPowers[index];
- DOUBLE_CONVERSION_ASSERT(min_exponent <= cached_power.binary_exponent);
- (void) max_exponent; // Mark variable as used.
- DOUBLE_CONVERSION_ASSERT(cached_power.binary_exponent <= max_exponent);
- *decimal_exponent = cached_power.decimal_exponent;
- *power = DiyFp(cached_power.significand, cached_power.binary_exponent);
-}
-
-
-void GetCachedPowerForDecimalExponent(int requested_exponent,
- DiyFp* power,
- int* found_exponent) {
- DOUBLE_CONVERSION_ASSERT(kMinDecimalExponent <= requested_exponent);
- DOUBLE_CONVERSION_ASSERT(requested_exponent < kMaxDecimalExponent + kDecimalExponentDistance);
- int index =
- (requested_exponent + kCachedPowersOffset) / kDecimalExponentDistance;
- CachedPower cached_power = kCachedPowers[index];
- *power = DiyFp(cached_power.significand, cached_power.binary_exponent);
- *found_exponent = cached_power.decimal_exponent;
- DOUBLE_CONVERSION_ASSERT(*found_exponent <= requested_exponent);
- DOUBLE_CONVERSION_ASSERT(requested_exponent < *found_exponent + kDecimalExponentDistance);
-}
-
-} // namespace PowersOfTenCache
-
-} // namespace double_conversion
-
-// ICU PATCH: Close ICU namespace
-U_NAMESPACE_END
-#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
+// © 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 2006-2008 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 <climits>
+#include <cmath>
+#include <cstdarg>
+
+// ICU PATCH: Customize header file paths for ICU.
+
+#include "double-conversion-utils.h"
+
+#include "double-conversion-cached-powers.h"
+
+// ICU PATCH: Wrap in ICU namespace
+U_NAMESPACE_BEGIN
+
+namespace double_conversion {
+
+namespace PowersOfTenCache {
+
+struct CachedPower {
+ uint64_t significand;
+ int16_t binary_exponent;
+ int16_t decimal_exponent;
+};
+
+static const CachedPower kCachedPowers[] = {
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xfa8fd5a0, 081c0288), -1220, -348},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xbaaee17f, a23ebf76), -1193, -340},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x8b16fb20, 3055ac76), -1166, -332},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xcf42894a, 5dce35ea), -1140, -324},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x9a6bb0aa, 55653b2d), -1113, -316},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xe61acf03, 3d1a45df), -1087, -308},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xab70fe17, c79ac6ca), -1060, -300},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xff77b1fc, bebcdc4f), -1034, -292},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xbe5691ef, 416bd60c), -1007, -284},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x8dd01fad, 907ffc3c), -980, -276},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xd3515c28, 31559a83), -954, -268},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x9d71ac8f, ada6c9b5), -927, -260},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xea9c2277, 23ee8bcb), -901, -252},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xaecc4991, 4078536d), -874, -244},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x823c1279, 5db6ce57), -847, -236},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xc2109436, 4dfb5637), -821, -228},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x9096ea6f, 3848984f), -794, -220},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xd77485cb, 25823ac7), -768, -212},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xa086cfcd, 97bf97f4), -741, -204},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xef340a98, 172aace5), -715, -196},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xb23867fb, 2a35b28e), -688, -188},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x84c8d4df, d2c63f3b), -661, -180},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xc5dd4427, 1ad3cdba), -635, -172},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x936b9fce, bb25c996), -608, -164},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xdbac6c24, 7d62a584), -582, -156},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xa3ab6658, 0d5fdaf6), -555, -148},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xf3e2f893, dec3f126), -529, -140},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xb5b5ada8, aaff80b8), -502, -132},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x87625f05, 6c7c4a8b), -475, -124},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xc9bcff60, 34c13053), -449, -116},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x964e858c, 91ba2655), -422, -108},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xdff97724, 70297ebd), -396, -100},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xa6dfbd9f, b8e5b88f), -369, -92},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xf8a95fcf, 88747d94), -343, -84},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xb9447093, 8fa89bcf), -316, -76},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x8a08f0f8, bf0f156b), -289, -68},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xcdb02555, 653131b6), -263, -60},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x993fe2c6, d07b7fac), -236, -52},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xe45c10c4, 2a2b3b06), -210, -44},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xaa242499, 697392d3), -183, -36},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xfd87b5f2, 8300ca0e), -157, -28},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xbce50864, 92111aeb), -130, -20},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x8cbccc09, 6f5088cc), -103, -12},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xd1b71758, e219652c), -77, -4},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x9c400000, 00000000), -50, 4},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xe8d4a510, 00000000), -24, 12},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xad78ebc5, ac620000), 3, 20},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x813f3978, f8940984), 30, 28},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xc097ce7b, c90715b3), 56, 36},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x8f7e32ce, 7bea5c70), 83, 44},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xd5d238a4, abe98068), 109, 52},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x9f4f2726, 179a2245), 136, 60},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xed63a231, d4c4fb27), 162, 68},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xb0de6538, 8cc8ada8), 189, 76},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x83c7088e, 1aab65db), 216, 84},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xc45d1df9, 42711d9a), 242, 92},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x924d692c, a61be758), 269, 100},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xda01ee64, 1a708dea), 295, 108},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xa26da399, 9aef774a), 322, 116},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xf209787b, b47d6b85), 348, 124},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xb454e4a1, 79dd1877), 375, 132},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x865b8692, 5b9bc5c2), 402, 140},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xc83553c5, c8965d3d), 428, 148},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x952ab45c, fa97a0b3), 455, 156},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xde469fbd, 99a05fe3), 481, 164},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xa59bc234, db398c25), 508, 172},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xf6c69a72, a3989f5c), 534, 180},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xb7dcbf53, 54e9bece), 561, 188},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x88fcf317, f22241e2), 588, 196},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xcc20ce9b, d35c78a5), 614, 204},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x98165af3, 7b2153df), 641, 212},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xe2a0b5dc, 971f303a), 667, 220},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xa8d9d153, 5ce3b396), 694, 228},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xfb9b7cd9, a4a7443c), 720, 236},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xbb764c4c, a7a44410), 747, 244},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x8bab8eef, b6409c1a), 774, 252},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xd01fef10, a657842c), 800, 260},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x9b10a4e5, e9913129), 827, 268},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xe7109bfb, a19c0c9d), 853, 276},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xac2820d9, 623bf429), 880, 284},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x80444b5e, 7aa7cf85), 907, 292},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xbf21e440, 03acdd2d), 933, 300},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x8e679c2f, 5e44ff8f), 960, 308},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xd433179d, 9c8cb841), 986, 316},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0x9e19db92, b4e31ba9), 1013, 324},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xeb96bf6e, badf77d9), 1039, 332},
+ {DOUBLE_CONVERSION_UINT64_2PART_C(0xaf87023b, 9bf0ee6b), 1066, 340},
+};
+
+static const int kCachedPowersOffset = 348; // -1 * the first decimal_exponent.
+static const double kD_1_LOG2_10 = 0.30102999566398114; // 1 / lg(10)
+
+void GetCachedPowerForBinaryExponentRange(
+ int min_exponent,
+ int max_exponent,
+ DiyFp* power,
+ int* decimal_exponent) {
+ int kQ = DiyFp::kSignificandSize;
+ double k = ceil((min_exponent + kQ - 1) * kD_1_LOG2_10);
+ int foo = kCachedPowersOffset;
+ int index =
+ (foo + static_cast<int>(k) - 1) / kDecimalExponentDistance + 1;
+ DOUBLE_CONVERSION_ASSERT(0 <= index && index < static_cast<int>(DOUBLE_CONVERSION_ARRAY_SIZE(kCachedPowers)));
+ CachedPower cached_power = kCachedPowers[index];
+ DOUBLE_CONVERSION_ASSERT(min_exponent <= cached_power.binary_exponent);
+ (void) max_exponent; // Mark variable as used.
+ DOUBLE_CONVERSION_ASSERT(cached_power.binary_exponent <= max_exponent);
+ *decimal_exponent = cached_power.decimal_exponent;
+ *power = DiyFp(cached_power.significand, cached_power.binary_exponent);
+}
+
+
+void GetCachedPowerForDecimalExponent(int requested_exponent,
+ DiyFp* power,
+ int* found_exponent) {
+ DOUBLE_CONVERSION_ASSERT(kMinDecimalExponent <= requested_exponent);
+ DOUBLE_CONVERSION_ASSERT(requested_exponent < kMaxDecimalExponent + kDecimalExponentDistance);
+ int index =
+ (requested_exponent + kCachedPowersOffset) / kDecimalExponentDistance;
+ CachedPower cached_power = kCachedPowers[index];
+ *power = DiyFp(cached_power.significand, cached_power.binary_exponent);
+ *found_exponent = cached_power.decimal_exponent;
+ DOUBLE_CONVERSION_ASSERT(*found_exponent <= requested_exponent);
+ DOUBLE_CONVERSION_ASSERT(requested_exponent < *found_exponent + kDecimalExponentDistance);
+}
+
+} // namespace PowersOfTenCache
+
+} // namespace double_conversion
+
+// ICU PATCH: Close ICU namespace
+U_NAMESPACE_END
+#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
diff --git a/contrib/libs/icu/i18n/double-conversion-cached-powers.h b/contrib/libs/icu/i18n/double-conversion-cached-powers.h
index ade27baef8..57cb3e9869 100644
--- a/contrib/libs/icu/i18n/double-conversion-cached-powers.h
+++ b/contrib/libs/icu/i18n/double-conversion-cached-powers.h
@@ -1,82 +1,82 @@
-// © 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_CACHED_POWERS_H_
-#define DOUBLE_CONVERSION_CACHED_POWERS_H_
-
-// ICU PATCH: Customize header file paths for ICU.
-
-#include "double-conversion-diy-fp.h"
-
-// ICU PATCH: Wrap in ICU namespace
-U_NAMESPACE_BEGIN
-
-namespace double_conversion {
-
-namespace PowersOfTenCache {
-
- // Not all powers of ten are cached. The decimal exponent of two neighboring
- // cached numbers will differ by kDecimalExponentDistance.
- static const int kDecimalExponentDistance = 8;
-
- static const int kMinDecimalExponent = -348;
- static const int kMaxDecimalExponent = 340;
-
- // Returns a cached power-of-ten with a binary exponent in the range
- // [min_exponent; max_exponent] (boundaries included).
- void GetCachedPowerForBinaryExponentRange(int min_exponent,
- int max_exponent,
- DiyFp* power,
- int* decimal_exponent);
-
- // Returns a cached power of ten x ~= 10^k such that
- // k <= decimal_exponent < k + kCachedPowersDecimalDistance.
- // The given decimal_exponent must satisfy
- // kMinDecimalExponent <= requested_exponent, and
- // requested_exponent < kMaxDecimalExponent + kDecimalExponentDistance.
- void GetCachedPowerForDecimalExponent(int requested_exponent,
- DiyFp* power,
- int* found_exponent);
-
-} // namespace PowersOfTenCache
-
-} // namespace double_conversion
-
-// ICU PATCH: Close ICU namespace
-U_NAMESPACE_END
-
-#endif // DOUBLE_CONVERSION_CACHED_POWERS_H_
-#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
+// © 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_CACHED_POWERS_H_
+#define DOUBLE_CONVERSION_CACHED_POWERS_H_
+
+// ICU PATCH: Customize header file paths for ICU.
+
+#include "double-conversion-diy-fp.h"
+
+// ICU PATCH: Wrap in ICU namespace
+U_NAMESPACE_BEGIN
+
+namespace double_conversion {
+
+namespace PowersOfTenCache {
+
+ // Not all powers of ten are cached. The decimal exponent of two neighboring
+ // cached numbers will differ by kDecimalExponentDistance.
+ static const int kDecimalExponentDistance = 8;
+
+ static const int kMinDecimalExponent = -348;
+ static const int kMaxDecimalExponent = 340;
+
+ // Returns a cached power-of-ten with a binary exponent in the range
+ // [min_exponent; max_exponent] (boundaries included).
+ void GetCachedPowerForBinaryExponentRange(int min_exponent,
+ int max_exponent,
+ DiyFp* power,
+ int* decimal_exponent);
+
+ // Returns a cached power of ten x ~= 10^k such that
+ // k <= decimal_exponent < k + kCachedPowersDecimalDistance.
+ // The given decimal_exponent must satisfy
+ // kMinDecimalExponent <= requested_exponent, and
+ // requested_exponent < kMaxDecimalExponent + kDecimalExponentDistance.
+ void GetCachedPowerForDecimalExponent(int requested_exponent,
+ DiyFp* power,
+ int* found_exponent);
+
+} // namespace PowersOfTenCache
+
+} // namespace double_conversion
+
+// ICU PATCH: Close ICU namespace
+U_NAMESPACE_END
+
+#endif // DOUBLE_CONVERSION_CACHED_POWERS_H_
+#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
diff --git a/contrib/libs/icu/i18n/double-conversion-diy-fp.h b/contrib/libs/icu/i18n/double-conversion-diy-fp.h
index 5820abedf3..c30b350365 100644
--- a/contrib/libs/icu/i18n/double-conversion-diy-fp.h
+++ b/contrib/libs/icu/i18n/double-conversion-diy-fp.h
@@ -1,155 +1,155 @@
-// © 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_DIY_FP_H_
-#define DOUBLE_CONVERSION_DIY_FP_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 {
-
-// This "Do It Yourself Floating Point" class implements a floating-point number
-// with a uint64 significand and an int exponent. Normalized DiyFp numbers will
-// have the most significant bit of the significand set.
-// Multiplication and Subtraction do not normalize their results.
-// DiyFp store only non-negative numbers and are not designed to contain special
-// doubles (NaN and Infinity).
-class DiyFp {
- public:
- static const int kSignificandSize = 64;
-
- DiyFp() : f_(0), e_(0) {}
- DiyFp(const uint64_t significand, const int32_t exponent) : f_(significand), e_(exponent) {}
-
- // this -= other.
- // The exponents of both numbers must be the same and the significand of this
- // must be greater or equal than the significand of other.
- // The result will not be normalized.
- void Subtract(const DiyFp& other) {
- DOUBLE_CONVERSION_ASSERT(e_ == other.e_);
- DOUBLE_CONVERSION_ASSERT(f_ >= other.f_);
- f_ -= other.f_;
- }
-
- // Returns a - b.
- // The exponents of both numbers must be the same and a must be greater
- // or equal than b. The result will not be normalized.
- static DiyFp Minus(const DiyFp& a, const DiyFp& b) {
- DiyFp result = a;
- result.Subtract(b);
- return result;
- }
-
- // this *= other.
- void Multiply(const DiyFp& other) {
- // Simply "emulates" a 128 bit multiplication.
- // However: the resulting number only contains 64 bits. The least
- // significant 64 bits are only used for rounding the most significant 64
- // bits.
- const uint64_t kM32 = 0xFFFFFFFFU;
- const uint64_t a = f_ >> 32;
- const uint64_t b = f_ & kM32;
- const uint64_t c = other.f_ >> 32;
- const uint64_t d = other.f_ & kM32;
- const uint64_t ac = a * c;
- const uint64_t bc = b * c;
- const uint64_t ad = a * d;
- const uint64_t bd = b * d;
- // By adding 1U << 31 to tmp we round the final result.
- // Halfway cases will be rounded up.
- const uint64_t tmp = (bd >> 32) + (ad & kM32) + (bc & kM32) + (1U << 31);
- e_ += other.e_ + 64;
- f_ = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32);
- }
-
- // returns a * b;
- static DiyFp Times(const DiyFp& a, const DiyFp& b) {
- DiyFp result = a;
- result.Multiply(b);
- return result;
- }
-
- void Normalize() {
- DOUBLE_CONVERSION_ASSERT(f_ != 0);
- uint64_t significand = f_;
- int32_t exponent = e_;
-
- // This method is mainly called for normalizing boundaries. In general,
- // boundaries need to be shifted by 10 bits, and we optimize for this case.
- const uint64_t k10MSBits = DOUBLE_CONVERSION_UINT64_2PART_C(0xFFC00000, 00000000);
- while ((significand & k10MSBits) == 0) {
- significand <<= 10;
- exponent -= 10;
- }
- while ((significand & kUint64MSB) == 0) {
- significand <<= 1;
- exponent--;
- }
- f_ = significand;
- e_ = exponent;
- }
-
- static DiyFp Normalize(const DiyFp& a) {
- DiyFp result = a;
- result.Normalize();
- return result;
- }
-
- uint64_t f() const { return f_; }
- int32_t e() const { return e_; }
-
- void set_f(uint64_t new_value) { f_ = new_value; }
- void set_e(int32_t new_value) { e_ = new_value; }
-
- private:
- static const uint64_t kUint64MSB = DOUBLE_CONVERSION_UINT64_2PART_C(0x80000000, 00000000);
-
- uint64_t f_;
- int32_t e_;
-};
-
-} // namespace double_conversion
-
-// ICU PATCH: Close ICU namespace
-U_NAMESPACE_END
-
-#endif // DOUBLE_CONVERSION_DIY_FP_H_
-#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
+// © 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_DIY_FP_H_
+#define DOUBLE_CONVERSION_DIY_FP_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 {
+
+// This "Do It Yourself Floating Point" class implements a floating-point number
+// with a uint64 significand and an int exponent. Normalized DiyFp numbers will
+// have the most significant bit of the significand set.
+// Multiplication and Subtraction do not normalize their results.
+// DiyFp store only non-negative numbers and are not designed to contain special
+// doubles (NaN and Infinity).
+class DiyFp {
+ public:
+ static const int kSignificandSize = 64;
+
+ DiyFp() : f_(0), e_(0) {}
+ DiyFp(const uint64_t significand, const int32_t exponent) : f_(significand), e_(exponent) {}
+
+ // this -= other.
+ // The exponents of both numbers must be the same and the significand of this
+ // must be greater or equal than the significand of other.
+ // The result will not be normalized.
+ void Subtract(const DiyFp& other) {
+ DOUBLE_CONVERSION_ASSERT(e_ == other.e_);
+ DOUBLE_CONVERSION_ASSERT(f_ >= other.f_);
+ f_ -= other.f_;
+ }
+
+ // Returns a - b.
+ // The exponents of both numbers must be the same and a must be greater
+ // or equal than b. The result will not be normalized.
+ static DiyFp Minus(const DiyFp& a, const DiyFp& b) {
+ DiyFp result = a;
+ result.Subtract(b);
+ return result;
+ }
+
+ // this *= other.
+ void Multiply(const DiyFp& other) {
+ // Simply "emulates" a 128 bit multiplication.
+ // However: the resulting number only contains 64 bits. The least
+ // significant 64 bits are only used for rounding the most significant 64
+ // bits.
+ const uint64_t kM32 = 0xFFFFFFFFU;
+ const uint64_t a = f_ >> 32;
+ const uint64_t b = f_ & kM32;
+ const uint64_t c = other.f_ >> 32;
+ const uint64_t d = other.f_ & kM32;
+ const uint64_t ac = a * c;
+ const uint64_t bc = b * c;
+ const uint64_t ad = a * d;
+ const uint64_t bd = b * d;
+ // By adding 1U << 31 to tmp we round the final result.
+ // Halfway cases will be rounded up.
+ const uint64_t tmp = (bd >> 32) + (ad & kM32) + (bc & kM32) + (1U << 31);
+ e_ += other.e_ + 64;
+ f_ = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32);
+ }
+
+ // returns a * b;
+ static DiyFp Times(const DiyFp& a, const DiyFp& b) {
+ DiyFp result = a;
+ result.Multiply(b);
+ return result;
+ }
+
+ void Normalize() {
+ DOUBLE_CONVERSION_ASSERT(f_ != 0);
+ uint64_t significand = f_;
+ int32_t exponent = e_;
+
+ // This method is mainly called for normalizing boundaries. In general,
+ // boundaries need to be shifted by 10 bits, and we optimize for this case.
+ const uint64_t k10MSBits = DOUBLE_CONVERSION_UINT64_2PART_C(0xFFC00000, 00000000);
+ while ((significand & k10MSBits) == 0) {
+ significand <<= 10;
+ exponent -= 10;
+ }
+ while ((significand & kUint64MSB) == 0) {
+ significand <<= 1;
+ exponent--;
+ }
+ f_ = significand;
+ e_ = exponent;
+ }
+
+ static DiyFp Normalize(const DiyFp& a) {
+ DiyFp result = a;
+ result.Normalize();
+ return result;
+ }
+
+ uint64_t f() const { return f_; }
+ int32_t e() const { return e_; }
+
+ void set_f(uint64_t new_value) { f_ = new_value; }
+ void set_e(int32_t new_value) { e_ = new_value; }
+
+ private:
+ static const uint64_t kUint64MSB = DOUBLE_CONVERSION_UINT64_2PART_C(0x80000000, 00000000);
+
+ uint64_t f_;
+ int32_t e_;
+};
+
+} // namespace double_conversion
+
+// ICU PATCH: Close ICU namespace
+U_NAMESPACE_END
+
+#endif // DOUBLE_CONVERSION_DIY_FP_H_
+#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
diff --git a/contrib/libs/icu/i18n/double-conversion-double-to-string.cpp b/contrib/libs/icu/i18n/double-conversion-double-to-string.cpp
index 44c176f4f9..11fa69be04 100644
--- a/contrib/libs/icu/i18n/double-conversion-double-to-string.cpp
+++ b/contrib/libs/icu/i18n/double-conversion-double-to-string.cpp
@@ -1,450 +1,450 @@
-// © 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 <algorithm>
-#include <climits>
-#include <cmath>
-
-// ICU PATCH: Customize header file paths for ICU.
-// The file fixed-dtoa.h is not needed.
-
-#include "double-conversion-double-to-string.h"
-
-#include "double-conversion-bignum-dtoa.h"
-#include "double-conversion-fast-dtoa.h"
-#include "double-conversion-ieee.h"
-#include "double-conversion-utils.h"
-
-// ICU PATCH: Wrap in ICU namespace
-U_NAMESPACE_BEGIN
-
-namespace double_conversion {
-
-#if 0 // not needed for ICU
-const DoubleToStringConverter& DoubleToStringConverter::EcmaScriptConverter() {
- int flags = UNIQUE_ZERO | EMIT_POSITIVE_EXPONENT_SIGN;
- static DoubleToStringConverter converter(flags,
- "Infinity",
- "NaN",
- 'e',
- -6, 21,
- 6, 0);
- return converter;
-}
-
-
-bool DoubleToStringConverter::HandleSpecialValues(
- double value,
- StringBuilder* result_builder) const {
- Double double_inspect(value);
- if (double_inspect.IsInfinite()) {
- if (infinity_symbol_ == NULL) return false;
- if (value < 0) {
- result_builder->AddCharacter('-');
- }
- result_builder->AddString(infinity_symbol_);
- return true;
- }
- if (double_inspect.IsNan()) {
- if (nan_symbol_ == NULL) return false;
- result_builder->AddString(nan_symbol_);
- return true;
- }
- return false;
-}
-
-
-void DoubleToStringConverter::CreateExponentialRepresentation(
- const char* decimal_digits,
- int length,
- int exponent,
- StringBuilder* result_builder) const {
- DOUBLE_CONVERSION_ASSERT(length != 0);
- result_builder->AddCharacter(decimal_digits[0]);
- if (length != 1) {
- result_builder->AddCharacter('.');
- result_builder->AddSubstring(&decimal_digits[1], length-1);
- }
- result_builder->AddCharacter(exponent_character_);
- if (exponent < 0) {
- result_builder->AddCharacter('-');
- exponent = -exponent;
- } else {
- if ((flags_ & EMIT_POSITIVE_EXPONENT_SIGN) != 0) {
- result_builder->AddCharacter('+');
- }
- }
- if (exponent == 0) {
- result_builder->AddCharacter('0');
- return;
- }
- DOUBLE_CONVERSION_ASSERT(exponent < 1e4);
- // Changing this constant requires updating the comment of DoubleToStringConverter constructor
- const int kMaxExponentLength = 5;
- char buffer[kMaxExponentLength + 1];
- buffer[kMaxExponentLength] = '\0';
- int first_char_pos = kMaxExponentLength;
- while (exponent > 0) {
- buffer[--first_char_pos] = '0' + (exponent % 10);
- exponent /= 10;
- }
- // Add prefix '0' to make exponent width >= min(min_exponent_with_, kMaxExponentLength)
- // For example: convert 1e+9 -> 1e+09, if min_exponent_with_ is set to 2
- while(kMaxExponentLength - first_char_pos < std::min(min_exponent_width_, kMaxExponentLength)) {
- buffer[--first_char_pos] = '0';
- }
- result_builder->AddSubstring(&buffer[first_char_pos],
- kMaxExponentLength - first_char_pos);
-}
-
-
-void DoubleToStringConverter::CreateDecimalRepresentation(
- const char* decimal_digits,
- int length,
- int decimal_point,
- int digits_after_point,
- StringBuilder* result_builder) const {
- // Create a representation that is padded with zeros if needed.
- if (decimal_point <= 0) {
- // "0.00000decimal_rep" or "0.000decimal_rep00".
- result_builder->AddCharacter('0');
- if (digits_after_point > 0) {
- result_builder->AddCharacter('.');
- result_builder->AddPadding('0', -decimal_point);
- DOUBLE_CONVERSION_ASSERT(length <= digits_after_point - (-decimal_point));
- result_builder->AddSubstring(decimal_digits, length);
- int remaining_digits = digits_after_point - (-decimal_point) - length;
- result_builder->AddPadding('0', remaining_digits);
- }
- } else if (decimal_point >= length) {
- // "decimal_rep0000.00000" or "decimal_rep.0000".
- result_builder->AddSubstring(decimal_digits, length);
- result_builder->AddPadding('0', decimal_point - length);
- if (digits_after_point > 0) {
- result_builder->AddCharacter('.');
- result_builder->AddPadding('0', digits_after_point);
- }
- } else {
- // "decima.l_rep000".
- DOUBLE_CONVERSION_ASSERT(digits_after_point > 0);
- result_builder->AddSubstring(decimal_digits, decimal_point);
- result_builder->AddCharacter('.');
- DOUBLE_CONVERSION_ASSERT(length - decimal_point <= digits_after_point);
- result_builder->AddSubstring(&decimal_digits[decimal_point],
- length - decimal_point);
- int remaining_digits = digits_after_point - (length - decimal_point);
- result_builder->AddPadding('0', remaining_digits);
- }
- if (digits_after_point == 0) {
- if ((flags_ & EMIT_TRAILING_DECIMAL_POINT) != 0) {
- result_builder->AddCharacter('.');
- }
- if ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) {
- result_builder->AddCharacter('0');
- }
- }
-}
-
-
-bool DoubleToStringConverter::ToShortestIeeeNumber(
- double value,
- StringBuilder* result_builder,
- DoubleToStringConverter::DtoaMode mode) const {
- DOUBLE_CONVERSION_ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE);
- if (Double(value).IsSpecial()) {
- return HandleSpecialValues(value, result_builder);
- }
-
- int decimal_point;
- bool sign;
- const int kDecimalRepCapacity = kBase10MaximalLength + 1;
- char decimal_rep[kDecimalRepCapacity];
- int decimal_rep_length;
-
- DoubleToAscii(value, mode, 0, decimal_rep, kDecimalRepCapacity,
- &sign, &decimal_rep_length, &decimal_point);
-
- bool unique_zero = (flags_ & UNIQUE_ZERO) != 0;
- if (sign && (value != 0.0 || !unique_zero)) {
- result_builder->AddCharacter('-');
- }
-
- int exponent = decimal_point - 1;
- if ((decimal_in_shortest_low_ <= exponent) &&
- (exponent < decimal_in_shortest_high_)) {
- CreateDecimalRepresentation(decimal_rep, decimal_rep_length,
- decimal_point,
- (std::max)(0, decimal_rep_length - decimal_point),
- result_builder);
- } else {
- CreateExponentialRepresentation(decimal_rep, decimal_rep_length, exponent,
- result_builder);
- }
- return true;
-}
-
-
-bool DoubleToStringConverter::ToFixed(double value,
- int requested_digits,
- StringBuilder* result_builder) const {
- DOUBLE_CONVERSION_ASSERT(kMaxFixedDigitsBeforePoint == 60);
- const double kFirstNonFixed = 1e60;
-
- if (Double(value).IsSpecial()) {
- return HandleSpecialValues(value, result_builder);
- }
-
- if (requested_digits > kMaxFixedDigitsAfterPoint) return false;
- if (value >= kFirstNonFixed || value <= -kFirstNonFixed) return false;
-
- // Find a sufficiently precise decimal representation of n.
- int decimal_point;
- bool sign;
- // Add space for the '\0' byte.
- const int kDecimalRepCapacity =
- kMaxFixedDigitsBeforePoint + kMaxFixedDigitsAfterPoint + 1;
- char decimal_rep[kDecimalRepCapacity];
- int decimal_rep_length;
- DoubleToAscii(value, FIXED, requested_digits,
- decimal_rep, kDecimalRepCapacity,
- &sign, &decimal_rep_length, &decimal_point);
-
- bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
- if (sign && (value != 0.0 || !unique_zero)) {
- result_builder->AddCharacter('-');
- }
-
- CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point,
- requested_digits, result_builder);
- return true;
-}
-
-
-bool DoubleToStringConverter::ToExponential(
- double value,
- int requested_digits,
- StringBuilder* result_builder) const {
- if (Double(value).IsSpecial()) {
- return HandleSpecialValues(value, result_builder);
- }
-
- if (requested_digits < -1) return false;
- if (requested_digits > kMaxExponentialDigits) return false;
-
- int decimal_point;
- bool sign;
- // Add space for digit before the decimal point and the '\0' character.
- const int kDecimalRepCapacity = kMaxExponentialDigits + 2;
- DOUBLE_CONVERSION_ASSERT(kDecimalRepCapacity > kBase10MaximalLength);
- char decimal_rep[kDecimalRepCapacity];
-#ifndef NDEBUG
- // Problem: there is an assert in StringBuilder::AddSubstring() that
- // will pass this buffer to strlen(), and this buffer is not generally
- // null-terminated.
- memset(decimal_rep, 0, sizeof(decimal_rep));
-#endif
- int decimal_rep_length;
-
- if (requested_digits == -1) {
- DoubleToAscii(value, SHORTEST, 0,
- decimal_rep, kDecimalRepCapacity,
- &sign, &decimal_rep_length, &decimal_point);
- } else {
- DoubleToAscii(value, PRECISION, requested_digits + 1,
- decimal_rep, kDecimalRepCapacity,
- &sign, &decimal_rep_length, &decimal_point);
- DOUBLE_CONVERSION_ASSERT(decimal_rep_length <= requested_digits + 1);
-
- for (int i = decimal_rep_length; i < requested_digits + 1; ++i) {
- decimal_rep[i] = '0';
- }
- decimal_rep_length = requested_digits + 1;
- }
-
- bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
- if (sign && (value != 0.0 || !unique_zero)) {
- result_builder->AddCharacter('-');
- }
-
- int exponent = decimal_point - 1;
- CreateExponentialRepresentation(decimal_rep,
- decimal_rep_length,
- exponent,
- result_builder);
- return true;
-}
-
-
-bool DoubleToStringConverter::ToPrecision(double value,
- int precision,
- StringBuilder* result_builder) const {
- if (Double(value).IsSpecial()) {
- return HandleSpecialValues(value, result_builder);
- }
-
- if (precision < kMinPrecisionDigits || precision > kMaxPrecisionDigits) {
- return false;
- }
-
- // Find a sufficiently precise decimal representation of n.
- int decimal_point;
- bool sign;
- // Add one for the terminating null character.
- const int kDecimalRepCapacity = kMaxPrecisionDigits + 1;
- char decimal_rep[kDecimalRepCapacity];
- int decimal_rep_length;
-
- DoubleToAscii(value, PRECISION, precision,
- decimal_rep, kDecimalRepCapacity,
- &sign, &decimal_rep_length, &decimal_point);
- DOUBLE_CONVERSION_ASSERT(decimal_rep_length <= precision);
-
- bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
- if (sign && (value != 0.0 || !unique_zero)) {
- result_builder->AddCharacter('-');
- }
-
- // The exponent if we print the number as x.xxeyyy. That is with the
- // decimal point after the first digit.
- int exponent = decimal_point - 1;
-
- int extra_zero = ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) ? 1 : 0;
- if ((-decimal_point + 1 > max_leading_padding_zeroes_in_precision_mode_) ||
- (decimal_point - precision + extra_zero >
- max_trailing_padding_zeroes_in_precision_mode_)) {
- // Fill buffer to contain 'precision' digits.
- // Usually the buffer is already at the correct length, but 'DoubleToAscii'
- // is allowed to return less characters.
- for (int i = decimal_rep_length; i < precision; ++i) {
- decimal_rep[i] = '0';
- }
-
- CreateExponentialRepresentation(decimal_rep,
- precision,
- exponent,
- result_builder);
- } else {
- CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point,
- (std::max)(0, precision - decimal_point),
- result_builder);
- }
- return true;
-}
-#endif // not needed for ICU
-
-
-static BignumDtoaMode DtoaToBignumDtoaMode(
- DoubleToStringConverter::DtoaMode dtoa_mode) {
- switch (dtoa_mode) {
- case DoubleToStringConverter::SHORTEST: return BIGNUM_DTOA_SHORTEST;
- case DoubleToStringConverter::SHORTEST_SINGLE:
- return BIGNUM_DTOA_SHORTEST_SINGLE;
- case DoubleToStringConverter::FIXED: return BIGNUM_DTOA_FIXED;
- case DoubleToStringConverter::PRECISION: return BIGNUM_DTOA_PRECISION;
- default:
- DOUBLE_CONVERSION_UNREACHABLE();
- }
-}
-
-
-void DoubleToStringConverter::DoubleToAscii(double v,
- DtoaMode mode,
- int requested_digits,
- char* buffer,
- int buffer_length,
- bool* sign,
- int* length,
- int* point) {
- Vector<char> vector(buffer, buffer_length);
- DOUBLE_CONVERSION_ASSERT(!Double(v).IsSpecial());
- DOUBLE_CONVERSION_ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE || requested_digits >= 0);
-
- if (Double(v).Sign() < 0) {
- *sign = true;
- v = -v;
- } else {
- *sign = false;
- }
-
- if (mode == PRECISION && requested_digits == 0) {
- vector[0] = '\0';
- *length = 0;
- return;
- }
-
- if (v == 0) {
- vector[0] = '0';
- vector[1] = '\0';
- *length = 1;
- *point = 1;
- return;
- }
-
- bool fast_worked;
- switch (mode) {
- case SHORTEST:
- fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST, 0, vector, length, point);
- break;
-#if 0 // not needed for ICU
- case SHORTEST_SINGLE:
- fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST_SINGLE, 0,
- vector, length, point);
- break;
- case FIXED:
- fast_worked = FastFixedDtoa(v, requested_digits, vector, length, point);
- break;
- case PRECISION:
- fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits,
- vector, length, point);
- break;
-#endif // not needed for ICU
- default:
- fast_worked = false;
- DOUBLE_CONVERSION_UNREACHABLE();
- }
- if (fast_worked) return;
-
- // If the fast dtoa didn't succeed use the slower bignum version.
- BignumDtoaMode bignum_mode = DtoaToBignumDtoaMode(mode);
- BignumDtoa(v, bignum_mode, requested_digits, vector, length, point);
- vector[*length] = '\0';
-}
-
-} // namespace double_conversion
-
-// ICU PATCH: Close ICU namespace
-U_NAMESPACE_END
-#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
+// © 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 <algorithm>
+#include <climits>
+#include <cmath>
+
+// ICU PATCH: Customize header file paths for ICU.
+// The file fixed-dtoa.h is not needed.
+
+#include "double-conversion-double-to-string.h"
+
+#include "double-conversion-bignum-dtoa.h"
+#include "double-conversion-fast-dtoa.h"
+#include "double-conversion-ieee.h"
+#include "double-conversion-utils.h"
+
+// ICU PATCH: Wrap in ICU namespace
+U_NAMESPACE_BEGIN
+
+namespace double_conversion {
+
+#if 0 // not needed for ICU
+const DoubleToStringConverter& DoubleToStringConverter::EcmaScriptConverter() {
+ int flags = UNIQUE_ZERO | EMIT_POSITIVE_EXPONENT_SIGN;
+ static DoubleToStringConverter converter(flags,
+ "Infinity",
+ "NaN",
+ 'e',
+ -6, 21,
+ 6, 0);
+ return converter;
+}
+
+
+bool DoubleToStringConverter::HandleSpecialValues(
+ double value,
+ StringBuilder* result_builder) const {
+ Double double_inspect(value);
+ if (double_inspect.IsInfinite()) {
+ if (infinity_symbol_ == NULL) return false;
+ if (value < 0) {
+ result_builder->AddCharacter('-');
+ }
+ result_builder->AddString(infinity_symbol_);
+ return true;
+ }
+ if (double_inspect.IsNan()) {
+ if (nan_symbol_ == NULL) return false;
+ result_builder->AddString(nan_symbol_);
+ return true;
+ }
+ return false;
+}
+
+
+void DoubleToStringConverter::CreateExponentialRepresentation(
+ const char* decimal_digits,
+ int length,
+ int exponent,
+ StringBuilder* result_builder) const {
+ DOUBLE_CONVERSION_ASSERT(length != 0);
+ result_builder->AddCharacter(decimal_digits[0]);
+ if (length != 1) {
+ result_builder->AddCharacter('.');
+ result_builder->AddSubstring(&decimal_digits[1], length-1);
+ }
+ result_builder->AddCharacter(exponent_character_);
+ if (exponent < 0) {
+ result_builder->AddCharacter('-');
+ exponent = -exponent;
+ } else {
+ if ((flags_ & EMIT_POSITIVE_EXPONENT_SIGN) != 0) {
+ result_builder->AddCharacter('+');
+ }
+ }
+ if (exponent == 0) {
+ result_builder->AddCharacter('0');
+ return;
+ }
+ DOUBLE_CONVERSION_ASSERT(exponent < 1e4);
+ // Changing this constant requires updating the comment of DoubleToStringConverter constructor
+ const int kMaxExponentLength = 5;
+ char buffer[kMaxExponentLength + 1];
+ buffer[kMaxExponentLength] = '\0';
+ int first_char_pos = kMaxExponentLength;
+ while (exponent > 0) {
+ buffer[--first_char_pos] = '0' + (exponent % 10);
+ exponent /= 10;
+ }
+ // Add prefix '0' to make exponent width >= min(min_exponent_with_, kMaxExponentLength)
+ // For example: convert 1e+9 -> 1e+09, if min_exponent_with_ is set to 2
+ while(kMaxExponentLength - first_char_pos < std::min(min_exponent_width_, kMaxExponentLength)) {
+ buffer[--first_char_pos] = '0';
+ }
+ result_builder->AddSubstring(&buffer[first_char_pos],
+ kMaxExponentLength - first_char_pos);
+}
+
+
+void DoubleToStringConverter::CreateDecimalRepresentation(
+ const char* decimal_digits,
+ int length,
+ int decimal_point,
+ int digits_after_point,
+ StringBuilder* result_builder) const {
+ // Create a representation that is padded with zeros if needed.
+ if (decimal_point <= 0) {
+ // "0.00000decimal_rep" or "0.000decimal_rep00".
+ result_builder->AddCharacter('0');
+ if (digits_after_point > 0) {
+ result_builder->AddCharacter('.');
+ result_builder->AddPadding('0', -decimal_point);
+ DOUBLE_CONVERSION_ASSERT(length <= digits_after_point - (-decimal_point));
+ result_builder->AddSubstring(decimal_digits, length);
+ int remaining_digits = digits_after_point - (-decimal_point) - length;
+ result_builder->AddPadding('0', remaining_digits);
+ }
+ } else if (decimal_point >= length) {
+ // "decimal_rep0000.00000" or "decimal_rep.0000".
+ result_builder->AddSubstring(decimal_digits, length);
+ result_builder->AddPadding('0', decimal_point - length);
+ if (digits_after_point > 0) {
+ result_builder->AddCharacter('.');
+ result_builder->AddPadding('0', digits_after_point);
+ }
+ } else {
+ // "decima.l_rep000".
+ DOUBLE_CONVERSION_ASSERT(digits_after_point > 0);
+ result_builder->AddSubstring(decimal_digits, decimal_point);
+ result_builder->AddCharacter('.');
+ DOUBLE_CONVERSION_ASSERT(length - decimal_point <= digits_after_point);
+ result_builder->AddSubstring(&decimal_digits[decimal_point],
+ length - decimal_point);
+ int remaining_digits = digits_after_point - (length - decimal_point);
+ result_builder->AddPadding('0', remaining_digits);
+ }
+ if (digits_after_point == 0) {
+ if ((flags_ & EMIT_TRAILING_DECIMAL_POINT) != 0) {
+ result_builder->AddCharacter('.');
+ }
+ if ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) {
+ result_builder->AddCharacter('0');
+ }
+ }
+}
+
+
+bool DoubleToStringConverter::ToShortestIeeeNumber(
+ double value,
+ StringBuilder* result_builder,
+ DoubleToStringConverter::DtoaMode mode) const {
+ DOUBLE_CONVERSION_ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE);
+ if (Double(value).IsSpecial()) {
+ return HandleSpecialValues(value, result_builder);
+ }
+
+ int decimal_point;
+ bool sign;
+ const int kDecimalRepCapacity = kBase10MaximalLength + 1;
+ char decimal_rep[kDecimalRepCapacity];
+ int decimal_rep_length;
+
+ DoubleToAscii(value, mode, 0, decimal_rep, kDecimalRepCapacity,
+ &sign, &decimal_rep_length, &decimal_point);
+
+ bool unique_zero = (flags_ & UNIQUE_ZERO) != 0;
+ if (sign && (value != 0.0 || !unique_zero)) {
+ result_builder->AddCharacter('-');
+ }
+
+ int exponent = decimal_point - 1;
+ if ((decimal_in_shortest_low_ <= exponent) &&
+ (exponent < decimal_in_shortest_high_)) {
+ CreateDecimalRepresentation(decimal_rep, decimal_rep_length,
+ decimal_point,
+ (std::max)(0, decimal_rep_length - decimal_point),
+ result_builder);
+ } else {
+ CreateExponentialRepresentation(decimal_rep, decimal_rep_length, exponent,
+ result_builder);
+ }
+ return true;
+}
+
+
+bool DoubleToStringConverter::ToFixed(double value,
+ int requested_digits,
+ StringBuilder* result_builder) const {
+ DOUBLE_CONVERSION_ASSERT(kMaxFixedDigitsBeforePoint == 60);
+ const double kFirstNonFixed = 1e60;
+
+ if (Double(value).IsSpecial()) {
+ return HandleSpecialValues(value, result_builder);
+ }
+
+ if (requested_digits > kMaxFixedDigitsAfterPoint) return false;
+ if (value >= kFirstNonFixed || value <= -kFirstNonFixed) return false;
+
+ // Find a sufficiently precise decimal representation of n.
+ int decimal_point;
+ bool sign;
+ // Add space for the '\0' byte.
+ const int kDecimalRepCapacity =
+ kMaxFixedDigitsBeforePoint + kMaxFixedDigitsAfterPoint + 1;
+ char decimal_rep[kDecimalRepCapacity];
+ int decimal_rep_length;
+ DoubleToAscii(value, FIXED, requested_digits,
+ decimal_rep, kDecimalRepCapacity,
+ &sign, &decimal_rep_length, &decimal_point);
+
+ bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
+ if (sign && (value != 0.0 || !unique_zero)) {
+ result_builder->AddCharacter('-');
+ }
+
+ CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point,
+ requested_digits, result_builder);
+ return true;
+}
+
+
+bool DoubleToStringConverter::ToExponential(
+ double value,
+ int requested_digits,
+ StringBuilder* result_builder) const {
+ if (Double(value).IsSpecial()) {
+ return HandleSpecialValues(value, result_builder);
+ }
+
+ if (requested_digits < -1) return false;
+ if (requested_digits > kMaxExponentialDigits) return false;
+
+ int decimal_point;
+ bool sign;
+ // Add space for digit before the decimal point and the '\0' character.
+ const int kDecimalRepCapacity = kMaxExponentialDigits + 2;
+ DOUBLE_CONVERSION_ASSERT(kDecimalRepCapacity > kBase10MaximalLength);
+ char decimal_rep[kDecimalRepCapacity];
+#ifndef NDEBUG
+ // Problem: there is an assert in StringBuilder::AddSubstring() that
+ // will pass this buffer to strlen(), and this buffer is not generally
+ // null-terminated.
+ memset(decimal_rep, 0, sizeof(decimal_rep));
+#endif
+ int decimal_rep_length;
+
+ if (requested_digits == -1) {
+ DoubleToAscii(value, SHORTEST, 0,
+ decimal_rep, kDecimalRepCapacity,
+ &sign, &decimal_rep_length, &decimal_point);
+ } else {
+ DoubleToAscii(value, PRECISION, requested_digits + 1,
+ decimal_rep, kDecimalRepCapacity,
+ &sign, &decimal_rep_length, &decimal_point);
+ DOUBLE_CONVERSION_ASSERT(decimal_rep_length <= requested_digits + 1);
+
+ for (int i = decimal_rep_length; i < requested_digits + 1; ++i) {
+ decimal_rep[i] = '0';
+ }
+ decimal_rep_length = requested_digits + 1;
+ }
+
+ bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
+ if (sign && (value != 0.0 || !unique_zero)) {
+ result_builder->AddCharacter('-');
+ }
+
+ int exponent = decimal_point - 1;
+ CreateExponentialRepresentation(decimal_rep,
+ decimal_rep_length,
+ exponent,
+ result_builder);
+ return true;
+}
+
+
+bool DoubleToStringConverter::ToPrecision(double value,
+ int precision,
+ StringBuilder* result_builder) const {
+ if (Double(value).IsSpecial()) {
+ return HandleSpecialValues(value, result_builder);
+ }
+
+ if (precision < kMinPrecisionDigits || precision > kMaxPrecisionDigits) {
+ return false;
+ }
+
+ // Find a sufficiently precise decimal representation of n.
+ int decimal_point;
+ bool sign;
+ // Add one for the terminating null character.
+ const int kDecimalRepCapacity = kMaxPrecisionDigits + 1;
+ char decimal_rep[kDecimalRepCapacity];
+ int decimal_rep_length;
+
+ DoubleToAscii(value, PRECISION, precision,
+ decimal_rep, kDecimalRepCapacity,
+ &sign, &decimal_rep_length, &decimal_point);
+ DOUBLE_CONVERSION_ASSERT(decimal_rep_length <= precision);
+
+ bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
+ if (sign && (value != 0.0 || !unique_zero)) {
+ result_builder->AddCharacter('-');
+ }
+
+ // The exponent if we print the number as x.xxeyyy. That is with the
+ // decimal point after the first digit.
+ int exponent = decimal_point - 1;
+
+ int extra_zero = ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) ? 1 : 0;
+ if ((-decimal_point + 1 > max_leading_padding_zeroes_in_precision_mode_) ||
+ (decimal_point - precision + extra_zero >
+ max_trailing_padding_zeroes_in_precision_mode_)) {
+ // Fill buffer to contain 'precision' digits.
+ // Usually the buffer is already at the correct length, but 'DoubleToAscii'
+ // is allowed to return less characters.
+ for (int i = decimal_rep_length; i < precision; ++i) {
+ decimal_rep[i] = '0';
+ }
+
+ CreateExponentialRepresentation(decimal_rep,
+ precision,
+ exponent,
+ result_builder);
+ } else {
+ CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point,
+ (std::max)(0, precision - decimal_point),
+ result_builder);
+ }
+ return true;
+}
+#endif // not needed for ICU
+
+
+static BignumDtoaMode DtoaToBignumDtoaMode(
+ DoubleToStringConverter::DtoaMode dtoa_mode) {
+ switch (dtoa_mode) {
+ case DoubleToStringConverter::SHORTEST: return BIGNUM_DTOA_SHORTEST;
+ case DoubleToStringConverter::SHORTEST_SINGLE:
+ return BIGNUM_DTOA_SHORTEST_SINGLE;
+ case DoubleToStringConverter::FIXED: return BIGNUM_DTOA_FIXED;
+ case DoubleToStringConverter::PRECISION: return BIGNUM_DTOA_PRECISION;
+ default:
+ DOUBLE_CONVERSION_UNREACHABLE();
+ }
+}
+
+
+void DoubleToStringConverter::DoubleToAscii(double v,
+ DtoaMode mode,
+ int requested_digits,
+ char* buffer,
+ int buffer_length,
+ bool* sign,
+ int* length,
+ int* point) {
+ Vector<char> vector(buffer, buffer_length);
+ DOUBLE_CONVERSION_ASSERT(!Double(v).IsSpecial());
+ DOUBLE_CONVERSION_ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE || requested_digits >= 0);
+
+ if (Double(v).Sign() < 0) {
+ *sign = true;
+ v = -v;
+ } else {
+ *sign = false;
+ }
+
+ if (mode == PRECISION && requested_digits == 0) {
+ vector[0] = '\0';
+ *length = 0;
+ return;
+ }
+
+ if (v == 0) {
+ vector[0] = '0';
+ vector[1] = '\0';
+ *length = 1;
+ *point = 1;
+ return;
+ }
+
+ bool fast_worked;
+ switch (mode) {
+ case SHORTEST:
+ fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST, 0, vector, length, point);
+ break;
+#if 0 // not needed for ICU
+ case SHORTEST_SINGLE:
+ fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST_SINGLE, 0,
+ vector, length, point);
+ break;
+ case FIXED:
+ fast_worked = FastFixedDtoa(v, requested_digits, vector, length, point);
+ break;
+ case PRECISION:
+ fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits,
+ vector, length, point);
+ break;
+#endif // not needed for ICU
+ default:
+ fast_worked = false;
+ DOUBLE_CONVERSION_UNREACHABLE();
+ }
+ if (fast_worked) return;
+
+ // If the fast dtoa didn't succeed use the slower bignum version.
+ BignumDtoaMode bignum_mode = DtoaToBignumDtoaMode(mode);
+ BignumDtoa(v, bignum_mode, requested_digits, vector, length, point);
+ vector[*length] = '\0';
+}
+
+} // namespace double_conversion
+
+// ICU PATCH: Close ICU namespace
+U_NAMESPACE_END
+#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
diff --git a/contrib/libs/icu/i18n/double-conversion-double-to-string.h b/contrib/libs/icu/i18n/double-conversion-double-to-string.h
index 27bd867848..9e45fc7a5e 100644
--- a/contrib/libs/icu/i18n/double-conversion-double-to-string.h
+++ b/contrib/libs/icu/i18n/double-conversion-double-to-string.h
@@ -1,419 +1,419 @@
-// © 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 2012 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_DOUBLE_TO_STRING_H_
-#define DOUBLE_CONVERSION_DOUBLE_TO_STRING_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 {
-
-class DoubleToStringConverter {
- public:
-#if 0 // not needed for ICU
- // When calling ToFixed with a double > 10^kMaxFixedDigitsBeforePoint
- // or a requested_digits parameter > kMaxFixedDigitsAfterPoint then the
- // function returns false.
- static const int kMaxFixedDigitsBeforePoint = 60;
- static const int kMaxFixedDigitsAfterPoint = 60;
-
- // When calling ToExponential with a requested_digits
- // parameter > kMaxExponentialDigits then the function returns false.
- static const int kMaxExponentialDigits = 120;
-
- // When calling ToPrecision with a requested_digits
- // parameter < kMinPrecisionDigits or requested_digits > kMaxPrecisionDigits
- // then the function returns false.
- static const int kMinPrecisionDigits = 1;
- static const int kMaxPrecisionDigits = 120;
-
- enum Flags {
- NO_FLAGS = 0,
- EMIT_POSITIVE_EXPONENT_SIGN = 1,
- EMIT_TRAILING_DECIMAL_POINT = 2,
- EMIT_TRAILING_ZERO_AFTER_POINT = 4,
- UNIQUE_ZERO = 8
- };
-
- // Flags should be a bit-or combination of the possible Flags-enum.
- // - NO_FLAGS: no special flags.
- // - EMIT_POSITIVE_EXPONENT_SIGN: when the number is converted into exponent
- // form, emits a '+' for positive exponents. Example: 1.2e+2.
- // - EMIT_TRAILING_DECIMAL_POINT: when the input number is an integer and is
- // converted into decimal format then a trailing decimal point is appended.
- // Example: 2345.0 is converted to "2345.".
- // - EMIT_TRAILING_ZERO_AFTER_POINT: in addition to a trailing decimal point
- // emits a trailing '0'-character. This flag requires the
- // EXMIT_TRAILING_DECIMAL_POINT flag.
- // Example: 2345.0 is converted to "2345.0".
- // - UNIQUE_ZERO: "-0.0" is converted to "0.0".
- //
- // Infinity symbol and nan_symbol provide the string representation for these
- // special values. If the string is NULL and the special value is encountered
- // then the conversion functions return false.
- //
- // The exponent_character is used in exponential representations. It is
- // usually 'e' or 'E'.
- //
- // When converting to the shortest representation the converter will
- // represent input numbers in decimal format if they are in the interval
- // [10^decimal_in_shortest_low; 10^decimal_in_shortest_high[
- // (lower boundary included, greater boundary excluded).
- // Example: with decimal_in_shortest_low = -6 and
- // decimal_in_shortest_high = 21:
- // ToShortest(0.000001) -> "0.000001"
- // ToShortest(0.0000001) -> "1e-7"
- // ToShortest(111111111111111111111.0) -> "111111111111111110000"
- // ToShortest(100000000000000000000.0) -> "100000000000000000000"
- // ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21"
- //
- // When converting to precision mode the converter may add
- // max_leading_padding_zeroes before returning the number in exponential
- // format.
- // Example with max_leading_padding_zeroes_in_precision_mode = 6.
- // ToPrecision(0.0000012345, 2) -> "0.0000012"
- // ToPrecision(0.00000012345, 2) -> "1.2e-7"
- // Similarily the converter may add up to
- // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid
- // returning an exponential representation. A zero added by the
- // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit.
- // Examples for max_trailing_padding_zeroes_in_precision_mode = 1:
- // ToPrecision(230.0, 2) -> "230"
- // ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT.
- // ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT.
- //
- // The min_exponent_width is used for exponential representations.
- // The converter adds leading '0's to the exponent until the exponent
- // is at least min_exponent_width digits long.
- // The min_exponent_width is clamped to 5.
- // As such, the exponent may never have more than 5 digits in total.
- DoubleToStringConverter(int flags,
- const char* infinity_symbol,
- const char* nan_symbol,
- char exponent_character,
- int decimal_in_shortest_low,
- int decimal_in_shortest_high,
- int max_leading_padding_zeroes_in_precision_mode,
- int max_trailing_padding_zeroes_in_precision_mode,
- int min_exponent_width = 0)
- : flags_(flags),
- infinity_symbol_(infinity_symbol),
- nan_symbol_(nan_symbol),
- exponent_character_(exponent_character),
- decimal_in_shortest_low_(decimal_in_shortest_low),
- decimal_in_shortest_high_(decimal_in_shortest_high),
- max_leading_padding_zeroes_in_precision_mode_(
- max_leading_padding_zeroes_in_precision_mode),
- max_trailing_padding_zeroes_in_precision_mode_(
- max_trailing_padding_zeroes_in_precision_mode),
- min_exponent_width_(min_exponent_width) {
- // When 'trailing zero after the point' is set, then 'trailing point'
- // must be set too.
- DOUBLE_CONVERSION_ASSERT(((flags & EMIT_TRAILING_DECIMAL_POINT) != 0) ||
- !((flags & EMIT_TRAILING_ZERO_AFTER_POINT) != 0));
- }
-
- // Returns a converter following the EcmaScript specification.
- static const DoubleToStringConverter& EcmaScriptConverter();
-
- // Computes the shortest string of digits that correctly represent the input
- // number. Depending on decimal_in_shortest_low and decimal_in_shortest_high
- // (see constructor) it then either returns a decimal representation, or an
- // exponential representation.
- // Example with decimal_in_shortest_low = -6,
- // decimal_in_shortest_high = 21,
- // EMIT_POSITIVE_EXPONENT_SIGN activated, and
- // EMIT_TRAILING_DECIMAL_POINT deactived:
- // ToShortest(0.000001) -> "0.000001"
- // ToShortest(0.0000001) -> "1e-7"
- // ToShortest(111111111111111111111.0) -> "111111111111111110000"
- // ToShortest(100000000000000000000.0) -> "100000000000000000000"
- // ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21"
- //
- // Note: the conversion may round the output if the returned string
- // is accurate enough to uniquely identify the input-number.
- // For example the most precise representation of the double 9e59 equals
- // "899999999999999918767229449717619953810131273674690656206848", but
- // the converter will return the shorter (but still correct) "9e59".
- //
- // Returns true if the conversion succeeds. The conversion always succeeds
- // except when the input value is special and no infinity_symbol or
- // nan_symbol has been given to the constructor.
- bool ToShortest(double value, StringBuilder* result_builder) const {
- return ToShortestIeeeNumber(value, result_builder, SHORTEST);
- }
-
- // Same as ToShortest, but for single-precision floats.
- bool ToShortestSingle(float value, StringBuilder* result_builder) const {
- return ToShortestIeeeNumber(value, result_builder, SHORTEST_SINGLE);
- }
-
-
- // Computes a decimal representation with a fixed number of digits after the
- // decimal point. The last emitted digit is rounded.
- //
- // Examples:
- // ToFixed(3.12, 1) -> "3.1"
- // ToFixed(3.1415, 3) -> "3.142"
- // ToFixed(1234.56789, 4) -> "1234.5679"
- // ToFixed(1.23, 5) -> "1.23000"
- // ToFixed(0.1, 4) -> "0.1000"
- // ToFixed(1e30, 2) -> "1000000000000000019884624838656.00"
- // ToFixed(0.1, 30) -> "0.100000000000000005551115123126"
- // ToFixed(0.1, 17) -> "0.10000000000000001"
- //
- // If requested_digits equals 0, then the tail of the result depends on
- // the EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT.
- // Examples, for requested_digits == 0,
- // let EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT be
- // - false and false: then 123.45 -> 123
- // 0.678 -> 1
- // - true and false: then 123.45 -> 123.
- // 0.678 -> 1.
- // - true and true: then 123.45 -> 123.0
- // 0.678 -> 1.0
- //
- // Returns true if the conversion succeeds. The conversion always succeeds
- // except for the following cases:
- // - the input value is special and no infinity_symbol or nan_symbol has
- // been provided to the constructor,
- // - 'value' > 10^kMaxFixedDigitsBeforePoint, or
- // - 'requested_digits' > kMaxFixedDigitsAfterPoint.
- // The last two conditions imply that the result will never contain more than
- // 1 + kMaxFixedDigitsBeforePoint + 1 + kMaxFixedDigitsAfterPoint characters
- // (one additional character for the sign, and one for the decimal point).
- bool ToFixed(double value,
- int requested_digits,
- StringBuilder* result_builder) const;
-
- // Computes a representation in exponential format with requested_digits
- // after the decimal point. The last emitted digit is rounded.
- // If requested_digits equals -1, then the shortest exponential representation
- // is computed.
- //
- // Examples with EMIT_POSITIVE_EXPONENT_SIGN deactivated, and
- // exponent_character set to 'e'.
- // ToExponential(3.12, 1) -> "3.1e0"
- // ToExponential(5.0, 3) -> "5.000e0"
- // ToExponential(0.001, 2) -> "1.00e-3"
- // ToExponential(3.1415, -1) -> "3.1415e0"
- // ToExponential(3.1415, 4) -> "3.1415e0"
- // ToExponential(3.1415, 3) -> "3.142e0"
- // ToExponential(123456789000000, 3) -> "1.235e14"
- // ToExponential(1000000000000000019884624838656.0, -1) -> "1e30"
- // ToExponential(1000000000000000019884624838656.0, 32) ->
- // "1.00000000000000001988462483865600e30"
- // ToExponential(1234, 0) -> "1e3"
- //
- // Returns true if the conversion succeeds. The conversion always succeeds
- // except for the following cases:
- // - the input value is special and no infinity_symbol or nan_symbol has
- // been provided to the constructor,
- // - 'requested_digits' > kMaxExponentialDigits.
- // The last condition implies that the result will never contain more than
- // kMaxExponentialDigits + 8 characters (the sign, the digit before the
- // decimal point, the decimal point, the exponent character, the
- // exponent's sign, and at most 3 exponent digits).
- bool ToExponential(double value,
- int requested_digits,
- StringBuilder* result_builder) const;
-
- // Computes 'precision' leading digits of the given 'value' and returns them
- // either in exponential or decimal format, depending on
- // max_{leading|trailing}_padding_zeroes_in_precision_mode (given to the
- // constructor).
- // The last computed digit is rounded.
- //
- // Example with max_leading_padding_zeroes_in_precision_mode = 6.
- // ToPrecision(0.0000012345, 2) -> "0.0000012"
- // ToPrecision(0.00000012345, 2) -> "1.2e-7"
- // Similarily the converter may add up to
- // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid
- // returning an exponential representation. A zero added by the
- // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit.
- // Examples for max_trailing_padding_zeroes_in_precision_mode = 1:
- // ToPrecision(230.0, 2) -> "230"
- // ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT.
- // ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT.
- // Examples for max_trailing_padding_zeroes_in_precision_mode = 3, and no
- // EMIT_TRAILING_ZERO_AFTER_POINT:
- // ToPrecision(123450.0, 6) -> "123450"
- // ToPrecision(123450.0, 5) -> "123450"
- // ToPrecision(123450.0, 4) -> "123500"
- // ToPrecision(123450.0, 3) -> "123000"
- // ToPrecision(123450.0, 2) -> "1.2e5"
- //
- // Returns true if the conversion succeeds. The conversion always succeeds
- // except for the following cases:
- // - the input value is special and no infinity_symbol or nan_symbol has
- // been provided to the constructor,
- // - precision < kMinPericisionDigits
- // - precision > kMaxPrecisionDigits
- // The last condition implies that the result will never contain more than
- // kMaxPrecisionDigits + 7 characters (the sign, the decimal point, the
- // exponent character, the exponent's sign, and at most 3 exponent digits).
- bool ToPrecision(double value,
- int precision,
- StringBuilder* result_builder) const;
-#endif // not needed for ICU
-
- enum DtoaMode {
- // Produce the shortest correct representation.
- // For example the output of 0.299999999999999988897 is (the less accurate
- // but correct) 0.3.
- SHORTEST,
- // Same as SHORTEST, but for single-precision floats.
- SHORTEST_SINGLE,
- // Produce a fixed number of digits after the decimal point.
- // For instance fixed(0.1, 4) becomes 0.1000
- // If the input number is big, the output will be big.
- FIXED,
- // Fixed number of digits (independent of the decimal point).
- PRECISION
- };
-
- // The maximal number of digits that are needed to emit a double in base 10.
- // A higher precision can be achieved by using more digits, but the shortest
- // accurate representation of any double will never use more digits than
- // kBase10MaximalLength.
- // Note that DoubleToAscii null-terminates its input. So the given buffer
- // should be at least kBase10MaximalLength + 1 characters long.
- static const int kBase10MaximalLength = 17;
-
- // Converts the given double 'v' to digit characters. 'v' must not be NaN,
- // +Infinity, or -Infinity. In SHORTEST_SINGLE-mode this restriction also
- // applies to 'v' after it has been casted to a single-precision float. That
- // is, in this mode static_cast<float>(v) must not be NaN, +Infinity or
- // -Infinity.
- //
- // The result should be interpreted as buffer * 10^(point-length).
- //
- // The digits are written to the buffer in the platform's charset, which is
- // often UTF-8 (with ASCII-range digits) but may be another charset, such
- // as EBCDIC.
- //
- // The output depends on the given mode:
- // - SHORTEST: produce the least amount of digits for which the internal
- // identity requirement is still satisfied. If the digits are printed
- // (together with the correct exponent) then reading this number will give
- // 'v' again. The buffer will choose the representation that is closest to
- // 'v'. If there are two at the same distance, than the one farther away
- // from 0 is chosen (halfway cases - ending with 5 - are rounded up).
- // In this mode the 'requested_digits' parameter is ignored.
- // - SHORTEST_SINGLE: same as SHORTEST but with single-precision.
- // - FIXED: produces digits necessary to print a given number with
- // 'requested_digits' digits after the decimal point. The produced digits
- // might be too short in which case the caller has to fill the remainder
- // with '0's.
- // Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2.
- // Halfway cases are rounded towards +/-Infinity (away from 0). The call
- // toFixed(0.15, 2) thus returns buffer="2", point=0.
- // The returned buffer may contain digits that would be truncated from the
- // shortest representation of the input.
- // - PRECISION: produces 'requested_digits' where the first digit is not '0'.
- // Even though the length of produced digits usually equals
- // 'requested_digits', the function is allowed to return fewer digits, in
- // which case the caller has to fill the missing digits with '0's.
- // Halfway cases are again rounded away from 0.
- // DoubleToAscii expects the given buffer to be big enough to hold all
- // digits and a terminating null-character. In SHORTEST-mode it expects a
- // buffer of at least kBase10MaximalLength + 1. In all other modes the
- // requested_digits parameter and the padding-zeroes limit the size of the
- // output. Don't forget the decimal point, the exponent character and the
- // terminating null-character when computing the maximal output size.
- // The given length is only used in debug mode to ensure the buffer is big
- // enough.
- // ICU PATCH: Export this as U_I18N_API for unit tests.
- static void U_I18N_API DoubleToAscii(double v,
- DtoaMode mode,
- int requested_digits,
- char* buffer,
- int buffer_length,
- bool* sign,
- int* length,
- int* point);
-
-#if 0 // not needed for ICU
- private:
- // Implementation for ToShortest and ToShortestSingle.
- bool ToShortestIeeeNumber(double value,
- StringBuilder* result_builder,
- DtoaMode mode) const;
-
- // If the value is a special value (NaN or Infinity) constructs the
- // corresponding string using the configured infinity/nan-symbol.
- // If either of them is NULL or the value is not special then the
- // function returns false.
- bool HandleSpecialValues(double value, StringBuilder* result_builder) const;
- // Constructs an exponential representation (i.e. 1.234e56).
- // The given exponent assumes a decimal point after the first decimal digit.
- void CreateExponentialRepresentation(const char* decimal_digits,
- int length,
- int exponent,
- StringBuilder* result_builder) const;
- // Creates a decimal representation (i.e 1234.5678).
- void CreateDecimalRepresentation(const char* decimal_digits,
- int length,
- int decimal_point,
- int digits_after_point,
- StringBuilder* result_builder) const;
-
- const int flags_;
- const char* const infinity_symbol_;
- const char* const nan_symbol_;
- const char exponent_character_;
- const int decimal_in_shortest_low_;
- const int decimal_in_shortest_high_;
- const int max_leading_padding_zeroes_in_precision_mode_;
- const int max_trailing_padding_zeroes_in_precision_mode_;
- const int min_exponent_width_;
-#endif // not needed for ICU
-
- DOUBLE_CONVERSION_DISALLOW_IMPLICIT_CONSTRUCTORS(DoubleToStringConverter);
-};
-
-} // namespace double_conversion
-
-// ICU PATCH: Close ICU namespace
-U_NAMESPACE_END
-
-#endif // DOUBLE_CONVERSION_DOUBLE_TO_STRING_H_
-#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
+// © 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 2012 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_DOUBLE_TO_STRING_H_
+#define DOUBLE_CONVERSION_DOUBLE_TO_STRING_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 {
+
+class DoubleToStringConverter {
+ public:
+#if 0 // not needed for ICU
+ // When calling ToFixed with a double > 10^kMaxFixedDigitsBeforePoint
+ // or a requested_digits parameter > kMaxFixedDigitsAfterPoint then the
+ // function returns false.
+ static const int kMaxFixedDigitsBeforePoint = 60;
+ static const int kMaxFixedDigitsAfterPoint = 60;
+
+ // When calling ToExponential with a requested_digits
+ // parameter > kMaxExponentialDigits then the function returns false.
+ static const int kMaxExponentialDigits = 120;
+
+ // When calling ToPrecision with a requested_digits
+ // parameter < kMinPrecisionDigits or requested_digits > kMaxPrecisionDigits
+ // then the function returns false.
+ static const int kMinPrecisionDigits = 1;
+ static const int kMaxPrecisionDigits = 120;
+
+ enum Flags {
+ NO_FLAGS = 0,
+ EMIT_POSITIVE_EXPONENT_SIGN = 1,
+ EMIT_TRAILING_DECIMAL_POINT = 2,
+ EMIT_TRAILING_ZERO_AFTER_POINT = 4,
+ UNIQUE_ZERO = 8
+ };
+
+ // Flags should be a bit-or combination of the possible Flags-enum.
+ // - NO_FLAGS: no special flags.
+ // - EMIT_POSITIVE_EXPONENT_SIGN: when the number is converted into exponent
+ // form, emits a '+' for positive exponents. Example: 1.2e+2.
+ // - EMIT_TRAILING_DECIMAL_POINT: when the input number is an integer and is
+ // converted into decimal format then a trailing decimal point is appended.
+ // Example: 2345.0 is converted to "2345.".
+ // - EMIT_TRAILING_ZERO_AFTER_POINT: in addition to a trailing decimal point
+ // emits a trailing '0'-character. This flag requires the
+ // EXMIT_TRAILING_DECIMAL_POINT flag.
+ // Example: 2345.0 is converted to "2345.0".
+ // - UNIQUE_ZERO: "-0.0" is converted to "0.0".
+ //
+ // Infinity symbol and nan_symbol provide the string representation for these
+ // special values. If the string is NULL and the special value is encountered
+ // then the conversion functions return false.
+ //
+ // The exponent_character is used in exponential representations. It is
+ // usually 'e' or 'E'.
+ //
+ // When converting to the shortest representation the converter will
+ // represent input numbers in decimal format if they are in the interval
+ // [10^decimal_in_shortest_low; 10^decimal_in_shortest_high[
+ // (lower boundary included, greater boundary excluded).
+ // Example: with decimal_in_shortest_low = -6 and
+ // decimal_in_shortest_high = 21:
+ // ToShortest(0.000001) -> "0.000001"
+ // ToShortest(0.0000001) -> "1e-7"
+ // ToShortest(111111111111111111111.0) -> "111111111111111110000"
+ // ToShortest(100000000000000000000.0) -> "100000000000000000000"
+ // ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21"
+ //
+ // When converting to precision mode the converter may add
+ // max_leading_padding_zeroes before returning the number in exponential
+ // format.
+ // Example with max_leading_padding_zeroes_in_precision_mode = 6.
+ // ToPrecision(0.0000012345, 2) -> "0.0000012"
+ // ToPrecision(0.00000012345, 2) -> "1.2e-7"
+ // Similarily the converter may add up to
+ // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid
+ // returning an exponential representation. A zero added by the
+ // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit.
+ // Examples for max_trailing_padding_zeroes_in_precision_mode = 1:
+ // ToPrecision(230.0, 2) -> "230"
+ // ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT.
+ // ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT.
+ //
+ // The min_exponent_width is used for exponential representations.
+ // The converter adds leading '0's to the exponent until the exponent
+ // is at least min_exponent_width digits long.
+ // The min_exponent_width is clamped to 5.
+ // As such, the exponent may never have more than 5 digits in total.
+ DoubleToStringConverter(int flags,
+ const char* infinity_symbol,
+ const char* nan_symbol,
+ char exponent_character,
+ int decimal_in_shortest_low,
+ int decimal_in_shortest_high,
+ int max_leading_padding_zeroes_in_precision_mode,
+ int max_trailing_padding_zeroes_in_precision_mode,
+ int min_exponent_width = 0)
+ : flags_(flags),
+ infinity_symbol_(infinity_symbol),
+ nan_symbol_(nan_symbol),
+ exponent_character_(exponent_character),
+ decimal_in_shortest_low_(decimal_in_shortest_low),
+ decimal_in_shortest_high_(decimal_in_shortest_high),
+ max_leading_padding_zeroes_in_precision_mode_(
+ max_leading_padding_zeroes_in_precision_mode),
+ max_trailing_padding_zeroes_in_precision_mode_(
+ max_trailing_padding_zeroes_in_precision_mode),
+ min_exponent_width_(min_exponent_width) {
+ // When 'trailing zero after the point' is set, then 'trailing point'
+ // must be set too.
+ DOUBLE_CONVERSION_ASSERT(((flags & EMIT_TRAILING_DECIMAL_POINT) != 0) ||
+ !((flags & EMIT_TRAILING_ZERO_AFTER_POINT) != 0));
+ }
+
+ // Returns a converter following the EcmaScript specification.
+ static const DoubleToStringConverter& EcmaScriptConverter();
+
+ // Computes the shortest string of digits that correctly represent the input
+ // number. Depending on decimal_in_shortest_low and decimal_in_shortest_high
+ // (see constructor) it then either returns a decimal representation, or an
+ // exponential representation.
+ // Example with decimal_in_shortest_low = -6,
+ // decimal_in_shortest_high = 21,
+ // EMIT_POSITIVE_EXPONENT_SIGN activated, and
+ // EMIT_TRAILING_DECIMAL_POINT deactived:
+ // ToShortest(0.000001) -> "0.000001"
+ // ToShortest(0.0000001) -> "1e-7"
+ // ToShortest(111111111111111111111.0) -> "111111111111111110000"
+ // ToShortest(100000000000000000000.0) -> "100000000000000000000"
+ // ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21"
+ //
+ // Note: the conversion may round the output if the returned string
+ // is accurate enough to uniquely identify the input-number.
+ // For example the most precise representation of the double 9e59 equals
+ // "899999999999999918767229449717619953810131273674690656206848", but
+ // the converter will return the shorter (but still correct) "9e59".
+ //
+ // Returns true if the conversion succeeds. The conversion always succeeds
+ // except when the input value is special and no infinity_symbol or
+ // nan_symbol has been given to the constructor.
+ bool ToShortest(double value, StringBuilder* result_builder) const {
+ return ToShortestIeeeNumber(value, result_builder, SHORTEST);
+ }
+
+ // Same as ToShortest, but for single-precision floats.
+ bool ToShortestSingle(float value, StringBuilder* result_builder) const {
+ return ToShortestIeeeNumber(value, result_builder, SHORTEST_SINGLE);
+ }
+
+
+ // Computes a decimal representation with a fixed number of digits after the
+ // decimal point. The last emitted digit is rounded.
+ //
+ // Examples:
+ // ToFixed(3.12, 1) -> "3.1"
+ // ToFixed(3.1415, 3) -> "3.142"
+ // ToFixed(1234.56789, 4) -> "1234.5679"
+ // ToFixed(1.23, 5) -> "1.23000"
+ // ToFixed(0.1, 4) -> "0.1000"
+ // ToFixed(1e30, 2) -> "1000000000000000019884624838656.00"
+ // ToFixed(0.1, 30) -> "0.100000000000000005551115123126"
+ // ToFixed(0.1, 17) -> "0.10000000000000001"
+ //
+ // If requested_digits equals 0, then the tail of the result depends on
+ // the EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT.
+ // Examples, for requested_digits == 0,
+ // let EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT be
+ // - false and false: then 123.45 -> 123
+ // 0.678 -> 1
+ // - true and false: then 123.45 -> 123.
+ // 0.678 -> 1.
+ // - true and true: then 123.45 -> 123.0
+ // 0.678 -> 1.0
+ //
+ // Returns true if the conversion succeeds. The conversion always succeeds
+ // except for the following cases:
+ // - the input value is special and no infinity_symbol or nan_symbol has
+ // been provided to the constructor,
+ // - 'value' > 10^kMaxFixedDigitsBeforePoint, or
+ // - 'requested_digits' > kMaxFixedDigitsAfterPoint.
+ // The last two conditions imply that the result will never contain more than
+ // 1 + kMaxFixedDigitsBeforePoint + 1 + kMaxFixedDigitsAfterPoint characters
+ // (one additional character for the sign, and one for the decimal point).
+ bool ToFixed(double value,
+ int requested_digits,
+ StringBuilder* result_builder) const;
+
+ // Computes a representation in exponential format with requested_digits
+ // after the decimal point. The last emitted digit is rounded.
+ // If requested_digits equals -1, then the shortest exponential representation
+ // is computed.
+ //
+ // Examples with EMIT_POSITIVE_EXPONENT_SIGN deactivated, and
+ // exponent_character set to 'e'.
+ // ToExponential(3.12, 1) -> "3.1e0"
+ // ToExponential(5.0, 3) -> "5.000e0"
+ // ToExponential(0.001, 2) -> "1.00e-3"
+ // ToExponential(3.1415, -1) -> "3.1415e0"
+ // ToExponential(3.1415, 4) -> "3.1415e0"
+ // ToExponential(3.1415, 3) -> "3.142e0"
+ // ToExponential(123456789000000, 3) -> "1.235e14"
+ // ToExponential(1000000000000000019884624838656.0, -1) -> "1e30"
+ // ToExponential(1000000000000000019884624838656.0, 32) ->
+ // "1.00000000000000001988462483865600e30"
+ // ToExponential(1234, 0) -> "1e3"
+ //
+ // Returns true if the conversion succeeds. The conversion always succeeds
+ // except for the following cases:
+ // - the input value is special and no infinity_symbol or nan_symbol has
+ // been provided to the constructor,
+ // - 'requested_digits' > kMaxExponentialDigits.
+ // The last condition implies that the result will never contain more than
+ // kMaxExponentialDigits + 8 characters (the sign, the digit before the
+ // decimal point, the decimal point, the exponent character, the
+ // exponent's sign, and at most 3 exponent digits).
+ bool ToExponential(double value,
+ int requested_digits,
+ StringBuilder* result_builder) const;
+
+ // Computes 'precision' leading digits of the given 'value' and returns them
+ // either in exponential or decimal format, depending on
+ // max_{leading|trailing}_padding_zeroes_in_precision_mode (given to the
+ // constructor).
+ // The last computed digit is rounded.
+ //
+ // Example with max_leading_padding_zeroes_in_precision_mode = 6.
+ // ToPrecision(0.0000012345, 2) -> "0.0000012"
+ // ToPrecision(0.00000012345, 2) -> "1.2e-7"
+ // Similarily the converter may add up to
+ // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid
+ // returning an exponential representation. A zero added by the
+ // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit.
+ // Examples for max_trailing_padding_zeroes_in_precision_mode = 1:
+ // ToPrecision(230.0, 2) -> "230"
+ // ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT.
+ // ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT.
+ // Examples for max_trailing_padding_zeroes_in_precision_mode = 3, and no
+ // EMIT_TRAILING_ZERO_AFTER_POINT:
+ // ToPrecision(123450.0, 6) -> "123450"
+ // ToPrecision(123450.0, 5) -> "123450"
+ // ToPrecision(123450.0, 4) -> "123500"
+ // ToPrecision(123450.0, 3) -> "123000"
+ // ToPrecision(123450.0, 2) -> "1.2e5"
+ //
+ // Returns true if the conversion succeeds. The conversion always succeeds
+ // except for the following cases:
+ // - the input value is special and no infinity_symbol or nan_symbol has
+ // been provided to the constructor,
+ // - precision < kMinPericisionDigits
+ // - precision > kMaxPrecisionDigits
+ // The last condition implies that the result will never contain more than
+ // kMaxPrecisionDigits + 7 characters (the sign, the decimal point, the
+ // exponent character, the exponent's sign, and at most 3 exponent digits).
+ bool ToPrecision(double value,
+ int precision,
+ StringBuilder* result_builder) const;
+#endif // not needed for ICU
+
+ enum DtoaMode {
+ // Produce the shortest correct representation.
+ // For example the output of 0.299999999999999988897 is (the less accurate
+ // but correct) 0.3.
+ SHORTEST,
+ // Same as SHORTEST, but for single-precision floats.
+ SHORTEST_SINGLE,
+ // Produce a fixed number of digits after the decimal point.
+ // For instance fixed(0.1, 4) becomes 0.1000
+ // If the input number is big, the output will be big.
+ FIXED,
+ // Fixed number of digits (independent of the decimal point).
+ PRECISION
+ };
+
+ // The maximal number of digits that are needed to emit a double in base 10.
+ // A higher precision can be achieved by using more digits, but the shortest
+ // accurate representation of any double will never use more digits than
+ // kBase10MaximalLength.
+ // Note that DoubleToAscii null-terminates its input. So the given buffer
+ // should be at least kBase10MaximalLength + 1 characters long.
+ static const int kBase10MaximalLength = 17;
+
+ // Converts the given double 'v' to digit characters. 'v' must not be NaN,
+ // +Infinity, or -Infinity. In SHORTEST_SINGLE-mode this restriction also
+ // applies to 'v' after it has been casted to a single-precision float. That
+ // is, in this mode static_cast<float>(v) must not be NaN, +Infinity or
+ // -Infinity.
+ //
+ // The result should be interpreted as buffer * 10^(point-length).
+ //
+ // The digits are written to the buffer in the platform's charset, which is
+ // often UTF-8 (with ASCII-range digits) but may be another charset, such
+ // as EBCDIC.
+ //
+ // The output depends on the given mode:
+ // - SHORTEST: produce the least amount of digits for which the internal
+ // identity requirement is still satisfied. If the digits are printed
+ // (together with the correct exponent) then reading this number will give
+ // 'v' again. The buffer will choose the representation that is closest to
+ // 'v'. If there are two at the same distance, than the one farther away
+ // from 0 is chosen (halfway cases - ending with 5 - are rounded up).
+ // In this mode the 'requested_digits' parameter is ignored.
+ // - SHORTEST_SINGLE: same as SHORTEST but with single-precision.
+ // - FIXED: produces digits necessary to print a given number with
+ // 'requested_digits' digits after the decimal point. The produced digits
+ // might be too short in which case the caller has to fill the remainder
+ // with '0's.
+ // Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2.
+ // Halfway cases are rounded towards +/-Infinity (away from 0). The call
+ // toFixed(0.15, 2) thus returns buffer="2", point=0.
+ // The returned buffer may contain digits that would be truncated from the
+ // shortest representation of the input.
+ // - PRECISION: produces 'requested_digits' where the first digit is not '0'.
+ // Even though the length of produced digits usually equals
+ // 'requested_digits', the function is allowed to return fewer digits, in
+ // which case the caller has to fill the missing digits with '0's.
+ // Halfway cases are again rounded away from 0.
+ // DoubleToAscii expects the given buffer to be big enough to hold all
+ // digits and a terminating null-character. In SHORTEST-mode it expects a
+ // buffer of at least kBase10MaximalLength + 1. In all other modes the
+ // requested_digits parameter and the padding-zeroes limit the size of the
+ // output. Don't forget the decimal point, the exponent character and the
+ // terminating null-character when computing the maximal output size.
+ // The given length is only used in debug mode to ensure the buffer is big
+ // enough.
+ // ICU PATCH: Export this as U_I18N_API for unit tests.
+ static void U_I18N_API DoubleToAscii(double v,
+ DtoaMode mode,
+ int requested_digits,
+ char* buffer,
+ int buffer_length,
+ bool* sign,
+ int* length,
+ int* point);
+
+#if 0 // not needed for ICU
+ private:
+ // Implementation for ToShortest and ToShortestSingle.
+ bool ToShortestIeeeNumber(double value,
+ StringBuilder* result_builder,
+ DtoaMode mode) const;
+
+ // If the value is a special value (NaN or Infinity) constructs the
+ // corresponding string using the configured infinity/nan-symbol.
+ // If either of them is NULL or the value is not special then the
+ // function returns false.
+ bool HandleSpecialValues(double value, StringBuilder* result_builder) const;
+ // Constructs an exponential representation (i.e. 1.234e56).
+ // The given exponent assumes a decimal point after the first decimal digit.
+ void CreateExponentialRepresentation(const char* decimal_digits,
+ int length,
+ int exponent,
+ StringBuilder* result_builder) const;
+ // Creates a decimal representation (i.e 1234.5678).
+ void CreateDecimalRepresentation(const char* decimal_digits,
+ int length,
+ int decimal_point,
+ int digits_after_point,
+ StringBuilder* result_builder) const;
+
+ const int flags_;
+ const char* const infinity_symbol_;
+ const char* const nan_symbol_;
+ const char exponent_character_;
+ const int decimal_in_shortest_low_;
+ const int decimal_in_shortest_high_;
+ const int max_leading_padding_zeroes_in_precision_mode_;
+ const int max_trailing_padding_zeroes_in_precision_mode_;
+ const int min_exponent_width_;
+#endif // not needed for ICU
+
+ DOUBLE_CONVERSION_DISALLOW_IMPLICIT_CONSTRUCTORS(DoubleToStringConverter);
+};
+
+} // namespace double_conversion
+
+// ICU PATCH: Close ICU namespace
+U_NAMESPACE_END
+
+#endif // DOUBLE_CONVERSION_DOUBLE_TO_STRING_H_
+#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
diff --git a/contrib/libs/icu/i18n/double-conversion-fast-dtoa.cpp b/contrib/libs/icu/i18n/double-conversion-fast-dtoa.cpp
index 87a3d536bf..961adbf04b 100644
--- a/contrib/libs/icu/i18n/double-conversion-fast-dtoa.cpp
+++ b/contrib/libs/icu/i18n/double-conversion-fast-dtoa.cpp
@@ -1,683 +1,683 @@
-// © 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 2012 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
-
-// ICU PATCH: Customize header file paths for ICU.
-
-#include "double-conversion-fast-dtoa.h"
-
-#include "double-conversion-cached-powers.h"
-#include "double-conversion-diy-fp.h"
-#include "double-conversion-ieee.h"
-
-// ICU PATCH: Wrap in ICU namespace
-U_NAMESPACE_BEGIN
-
-namespace double_conversion {
-
-// The minimal and maximal target exponent define the range of w's binary
-// exponent, where 'w' is the result of multiplying the input by a cached power
-// of ten.
-//
-// A different range might be chosen on a different platform, to optimize digit
-// generation, but a smaller range requires more powers of ten to be cached.
-static const int kMinimalTargetExponent = -60;
-static const int kMaximalTargetExponent = -32;
-
-
-// Adjusts the last digit of the generated number, and screens out generated
-// solutions that may be inaccurate. A solution may be inaccurate if it is
-// outside the safe interval, or if we cannot prove that it is closer to the
-// input than a neighboring representation of the same length.
-//
-// Input: * buffer containing the digits of too_high / 10^kappa
-// * the buffer's length
-// * distance_too_high_w == (too_high - w).f() * unit
-// * unsafe_interval == (too_high - too_low).f() * unit
-// * rest = (too_high - buffer * 10^kappa).f() * unit
-// * ten_kappa = 10^kappa * unit
-// * unit = the common multiplier
-// Output: returns true if the buffer is guaranteed to contain the closest
-// representable number to the input.
-// Modifies the generated digits in the buffer to approach (round towards) w.
-static bool RoundWeed(Vector<char> buffer,
- int length,
- uint64_t distance_too_high_w,
- uint64_t unsafe_interval,
- uint64_t rest,
- uint64_t ten_kappa,
- uint64_t unit) {
- uint64_t small_distance = distance_too_high_w - unit;
- uint64_t big_distance = distance_too_high_w + unit;
- // Let w_low = too_high - big_distance, and
- // w_high = too_high - small_distance.
- // Note: w_low < w < w_high
- //
- // The real w (* unit) must lie somewhere inside the interval
- // ]w_low; w_high[ (often written as "(w_low; w_high)")
-
- // Basically the buffer currently contains a number in the unsafe interval
- // ]too_low; too_high[ with too_low < w < too_high
- //
- // too_high - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- // ^v 1 unit ^ ^ ^ ^
- // boundary_high --------------------- . . . .
- // ^v 1 unit . . . .
- // - - - - - - - - - - - - - - - - - - - + - - + - - - - - - . .
- // . . ^ . .
- // . big_distance . . .
- // . . . . rest
- // small_distance . . . .
- // v . . . .
- // w_high - - - - - - - - - - - - - - - - - - . . . .
- // ^v 1 unit . . . .
- // w ---------------------------------------- . . . .
- // ^v 1 unit v . . .
- // w_low - - - - - - - - - - - - - - - - - - - - - . . .
- // . . v
- // buffer --------------------------------------------------+-------+--------
- // . .
- // safe_interval .
- // v .
- // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .
- // ^v 1 unit .
- // boundary_low ------------------------- unsafe_interval
- // ^v 1 unit v
- // too_low - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- //
- //
- // Note that the value of buffer could lie anywhere inside the range too_low
- // to too_high.
- //
- // boundary_low, boundary_high and w are approximations of the real boundaries
- // and v (the input number). They are guaranteed to be precise up to one unit.
- // In fact the error is guaranteed to be strictly less than one unit.
- //
- // Anything that lies outside the unsafe interval is guaranteed not to round
- // to v when read again.
- // Anything that lies inside the safe interval is guaranteed to round to v
- // when read again.
- // If the number inside the buffer lies inside the unsafe interval but not
- // inside the safe interval then we simply do not know and bail out (returning
- // false).
- //
- // Similarly we have to take into account the imprecision of 'w' when finding
- // the closest representation of 'w'. If we have two potential
- // representations, and one is closer to both w_low and w_high, then we know
- // it is closer to the actual value v.
- //
- // By generating the digits of too_high we got the largest (closest to
- // too_high) buffer that is still in the unsafe interval. In the case where
- // w_high < buffer < too_high we try to decrement the buffer.
- // This way the buffer approaches (rounds towards) w.
- // There are 3 conditions that stop the decrementation process:
- // 1) the buffer is already below w_high
- // 2) decrementing the buffer would make it leave the unsafe interval
- // 3) decrementing the buffer would yield a number below w_high and farther
- // away than the current number. In other words:
- // (buffer{-1} < w_high) && w_high - buffer{-1} > buffer - w_high
- // Instead of using the buffer directly we use its distance to too_high.
- // Conceptually rest ~= too_high - buffer
- // We need to do the following tests in this order to avoid over- and
- // underflows.
- DOUBLE_CONVERSION_ASSERT(rest <= unsafe_interval);
- while (rest < small_distance && // Negated condition 1
- unsafe_interval - rest >= ten_kappa && // Negated condition 2
- (rest + ten_kappa < small_distance || // buffer{-1} > w_high
- small_distance - rest >= rest + ten_kappa - small_distance)) {
- buffer[length - 1]--;
- rest += ten_kappa;
- }
-
- // We have approached w+ as much as possible. We now test if approaching w-
- // would require changing the buffer. If yes, then we have two possible
- // representations close to w, but we cannot decide which one is closer.
- if (rest < big_distance &&
- unsafe_interval - rest >= ten_kappa &&
- (rest + ten_kappa < big_distance ||
- big_distance - rest > rest + ten_kappa - big_distance)) {
- return false;
- }
-
- // Weeding test.
- // The safe interval is [too_low + 2 ulp; too_high - 2 ulp]
- // Since too_low = too_high - unsafe_interval this is equivalent to
- // [too_high - unsafe_interval + 4 ulp; too_high - 2 ulp]
- // Conceptually we have: rest ~= too_high - buffer
- return (2 * unit <= rest) && (rest <= unsafe_interval - 4 * unit);
-}
-
-
-// Rounds the buffer upwards if the result is closer to v by possibly adding
-// 1 to the buffer. If the precision of the calculation is not sufficient to
-// round correctly, return false.
-// The rounding might shift the whole buffer in which case the kappa is
-// adjusted. For example "99", kappa = 3 might become "10", kappa = 4.
-//
-// If 2*rest > ten_kappa then the buffer needs to be round up.
-// rest can have an error of +/- 1 unit. This function accounts for the
-// imprecision and returns false, if the rounding direction cannot be
-// unambiguously determined.
-//
-// Precondition: rest < ten_kappa.
-static bool RoundWeedCounted(Vector<char> buffer,
- int length,
- uint64_t rest,
- uint64_t ten_kappa,
- uint64_t unit,
- int* kappa) {
- DOUBLE_CONVERSION_ASSERT(rest < ten_kappa);
- // The following tests are done in a specific order to avoid overflows. They
- // will work correctly with any uint64 values of rest < ten_kappa and unit.
- //
- // If the unit is too big, then we don't know which way to round. For example
- // a unit of 50 means that the real number lies within rest +/- 50. If
- // 10^kappa == 40 then there is no way to tell which way to round.
- if (unit >= ten_kappa) return false;
- // Even if unit is just half the size of 10^kappa we are already completely
- // lost. (And after the previous test we know that the expression will not
- // over/underflow.)
- if (ten_kappa - unit <= unit) return false;
- // If 2 * (rest + unit) <= 10^kappa we can safely round down.
- if ((ten_kappa - rest > rest) && (ten_kappa - 2 * rest >= 2 * unit)) {
- return true;
- }
- // If 2 * (rest - unit) >= 10^kappa, then we can safely round up.
- if ((rest > unit) && (ten_kappa - (rest - unit) <= (rest - unit))) {
- // Increment the last digit recursively until we find a non '9' digit.
- buffer[length - 1]++;
- for (int i = length - 1; i > 0; --i) {
- if (buffer[i] != '0' + 10) break;
- buffer[i] = '0';
- buffer[i - 1]++;
- }
- // If the first digit is now '0'+ 10 we had a buffer with all '9's. With the
- // exception of the first digit all digits are now '0'. Simply switch the
- // first digit to '1' and adjust the kappa. Example: "99" becomes "10" and
- // the power (the kappa) is increased.
- if (buffer[0] == '0' + 10) {
- buffer[0] = '1';
- (*kappa) += 1;
- }
- return true;
- }
- return false;
-}
-
-// Returns the biggest power of ten that is less than or equal to the given
-// number. We furthermore receive the maximum number of bits 'number' has.
-//
-// Returns power == 10^(exponent_plus_one-1) such that
-// power <= number < power * 10.
-// If number_bits == 0 then 0^(0-1) is returned.
-// The number of bits must be <= 32.
-// Precondition: number < (1 << (number_bits + 1)).
-
-// Inspired by the method for finding an integer log base 10 from here:
-// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
-static unsigned int const kSmallPowersOfTen[] =
- {0, 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000,
- 1000000000};
-
-static void BiggestPowerTen(uint32_t number,
- int number_bits,
- uint32_t* power,
- int* exponent_plus_one) {
- DOUBLE_CONVERSION_ASSERT(number < (1u << (number_bits + 1)));
- // 1233/4096 is approximately 1/lg(10).
- int exponent_plus_one_guess = ((number_bits + 1) * 1233 >> 12);
- // We increment to skip over the first entry in the kPowersOf10 table.
- // Note: kPowersOf10[i] == 10^(i-1).
- exponent_plus_one_guess++;
- // We don't have any guarantees that 2^number_bits <= number.
- if (number < kSmallPowersOfTen[exponent_plus_one_guess]) {
- exponent_plus_one_guess--;
- }
- *power = kSmallPowersOfTen[exponent_plus_one_guess];
- *exponent_plus_one = exponent_plus_one_guess;
-}
-
-// Generates the digits of input number w.
-// w is a floating-point number (DiyFp), consisting of a significand and an
-// exponent. Its exponent is bounded by kMinimalTargetExponent and
-// kMaximalTargetExponent.
-// Hence -60 <= w.e() <= -32.
-//
-// Returns false if it fails, in which case the generated digits in the buffer
-// should not be used.
-// Preconditions:
-// * low, w and high are correct up to 1 ulp (unit in the last place). That
-// is, their error must be less than a unit of their last digits.
-// * low.e() == w.e() == high.e()
-// * low < w < high, and taking into account their error: low~ <= high~
-// * kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent
-// Postconditions: returns false if procedure fails.
-// otherwise:
-// * buffer is not null-terminated, but len contains the number of digits.
-// * buffer contains the shortest possible decimal digit-sequence
-// such that LOW < buffer * 10^kappa < HIGH, where LOW and HIGH are the
-// correct values of low and high (without their error).
-// * if more than one decimal representation gives the minimal number of
-// decimal digits then the one closest to W (where W is the correct value
-// of w) is chosen.
-// Remark: this procedure takes into account the imprecision of its input
-// numbers. If the precision is not enough to guarantee all the postconditions
-// then false is returned. This usually happens rarely (~0.5%).
-//
-// Say, for the sake of example, that
-// w.e() == -48, and w.f() == 0x1234567890abcdef
-// w's value can be computed by w.f() * 2^w.e()
-// We can obtain w's integral digits by simply shifting w.f() by -w.e().
-// -> w's integral part is 0x1234
-// w's fractional part is therefore 0x567890abcdef.
-// Printing w's integral part is easy (simply print 0x1234 in decimal).
-// In order to print its fraction we repeatedly multiply the fraction by 10 and
-// get each digit. Example the first digit after the point would be computed by
-// (0x567890abcdef * 10) >> 48. -> 3
-// The whole thing becomes slightly more complicated because we want to stop
-// once we have enough digits. That is, once the digits inside the buffer
-// represent 'w' we can stop. Everything inside the interval low - high
-// represents w. However we have to pay attention to low, high and w's
-// imprecision.
-static bool DigitGen(DiyFp low,
- DiyFp w,
- DiyFp high,
- Vector<char> buffer,
- int* length,
- int* kappa) {
- DOUBLE_CONVERSION_ASSERT(low.e() == w.e() && w.e() == high.e());
- DOUBLE_CONVERSION_ASSERT(low.f() + 1 <= high.f() - 1);
- DOUBLE_CONVERSION_ASSERT(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent);
- // low, w and high are imprecise, but by less than one ulp (unit in the last
- // place).
- // If we remove (resp. add) 1 ulp from low (resp. high) we are certain that
- // the new numbers are outside of the interval we want the final
- // representation to lie in.
- // Inversely adding (resp. removing) 1 ulp from low (resp. high) would yield
- // numbers that are certain to lie in the interval. We will use this fact
- // later on.
- // We will now start by generating the digits within the uncertain
- // interval. Later we will weed out representations that lie outside the safe
- // interval and thus _might_ lie outside the correct interval.
- uint64_t unit = 1;
- DiyFp too_low = DiyFp(low.f() - unit, low.e());
- DiyFp too_high = DiyFp(high.f() + unit, high.e());
- // too_low and too_high are guaranteed to lie outside the interval we want the
- // generated number in.
- DiyFp unsafe_interval = DiyFp::Minus(too_high, too_low);
- // We now cut the input number into two parts: the integral digits and the
- // fractionals. We will not write any decimal separator though, but adapt
- // kappa instead.
- // Reminder: we are currently computing the digits (stored inside the buffer)
- // such that: too_low < buffer * 10^kappa < too_high
- // We use too_high for the digit_generation and stop as soon as possible.
- // If we stop early we effectively round down.
- DiyFp one = DiyFp(static_cast<uint64_t>(1) << -w.e(), w.e());
- // Division by one is a shift.
- uint32_t integrals = static_cast<uint32_t>(too_high.f() >> -one.e());
- // Modulo by one is an and.
- uint64_t fractionals = too_high.f() & (one.f() - 1);
- uint32_t divisor;
- int divisor_exponent_plus_one;
- BiggestPowerTen(integrals, DiyFp::kSignificandSize - (-one.e()),
- &divisor, &divisor_exponent_plus_one);
- *kappa = divisor_exponent_plus_one;
- *length = 0;
- // Loop invariant: buffer = too_high / 10^kappa (integer division)
- // The invariant holds for the first iteration: kappa has been initialized
- // with the divisor exponent + 1. And the divisor is the biggest power of ten
- // that is smaller than integrals.
- while (*kappa > 0) {
- int digit = integrals / divisor;
- DOUBLE_CONVERSION_ASSERT(digit <= 9);
- buffer[*length] = static_cast<char>('0' + digit);
- (*length)++;
- integrals %= divisor;
- (*kappa)--;
- // Note that kappa now equals the exponent of the divisor and that the
- // invariant thus holds again.
- uint64_t rest =
- (static_cast<uint64_t>(integrals) << -one.e()) + fractionals;
- // Invariant: too_high = buffer * 10^kappa + DiyFp(rest, one.e())
- // Reminder: unsafe_interval.e() == one.e()
- if (rest < unsafe_interval.f()) {
- // Rounding down (by not emitting the remaining digits) yields a number
- // that lies within the unsafe interval.
- return RoundWeed(buffer, *length, DiyFp::Minus(too_high, w).f(),
- unsafe_interval.f(), rest,
- static_cast<uint64_t>(divisor) << -one.e(), unit);
- }
- divisor /= 10;
- }
-
- // The integrals have been generated. We are at the point of the decimal
- // separator. In the following loop we simply multiply the remaining digits by
- // 10 and divide by one. We just need to pay attention to multiply associated
- // data (like the interval or 'unit'), too.
- // Note that the multiplication by 10 does not overflow, because w.e >= -60
- // and thus one.e >= -60.
- DOUBLE_CONVERSION_ASSERT(one.e() >= -60);
- DOUBLE_CONVERSION_ASSERT(fractionals < one.f());
- DOUBLE_CONVERSION_ASSERT(DOUBLE_CONVERSION_UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF) / 10 >= one.f());
- for (;;) {
- fractionals *= 10;
- unit *= 10;
- unsafe_interval.set_f(unsafe_interval.f() * 10);
- // Integer division by one.
- int digit = static_cast<int>(fractionals >> -one.e());
- DOUBLE_CONVERSION_ASSERT(digit <= 9);
- buffer[*length] = static_cast<char>('0' + digit);
- (*length)++;
- fractionals &= one.f() - 1; // Modulo by one.
- (*kappa)--;
- if (fractionals < unsafe_interval.f()) {
- return RoundWeed(buffer, *length, DiyFp::Minus(too_high, w).f() * unit,
- unsafe_interval.f(), fractionals, one.f(), unit);
- }
- }
-}
-
-
-
-// Generates (at most) requested_digits digits of input number w.
-// w is a floating-point number (DiyFp), consisting of a significand and an
-// exponent. Its exponent is bounded by kMinimalTargetExponent and
-// kMaximalTargetExponent.
-// Hence -60 <= w.e() <= -32.
-//
-// Returns false if it fails, in which case the generated digits in the buffer
-// should not be used.
-// Preconditions:
-// * w is correct up to 1 ulp (unit in the last place). That
-// is, its error must be strictly less than a unit of its last digit.
-// * kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent
-//
-// Postconditions: returns false if procedure fails.
-// otherwise:
-// * buffer is not null-terminated, but length contains the number of
-// digits.
-// * the representation in buffer is the most precise representation of
-// requested_digits digits.
-// * buffer contains at most requested_digits digits of w. If there are less
-// than requested_digits digits then some trailing '0's have been removed.
-// * kappa is such that
-// w = buffer * 10^kappa + eps with |eps| < 10^kappa / 2.
-//
-// Remark: This procedure takes into account the imprecision of its input
-// numbers. If the precision is not enough to guarantee all the postconditions
-// then false is returned. This usually happens rarely, but the failure-rate
-// increases with higher requested_digits.
-static bool DigitGenCounted(DiyFp w,
- int requested_digits,
- Vector<char> buffer,
- int* length,
- int* kappa) {
- DOUBLE_CONVERSION_ASSERT(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent);
- DOUBLE_CONVERSION_ASSERT(kMinimalTargetExponent >= -60);
- DOUBLE_CONVERSION_ASSERT(kMaximalTargetExponent <= -32);
- // w is assumed to have an error less than 1 unit. Whenever w is scaled we
- // also scale its error.
- uint64_t w_error = 1;
- // We cut the input number into two parts: the integral digits and the
- // fractional digits. We don't emit any decimal separator, but adapt kappa
- // instead. Example: instead of writing "1.2" we put "12" into the buffer and
- // increase kappa by 1.
- DiyFp one = DiyFp(static_cast<uint64_t>(1) << -w.e(), w.e());
- // Division by one is a shift.
- uint32_t integrals = static_cast<uint32_t>(w.f() >> -one.e());
- // Modulo by one is an and.
- uint64_t fractionals = w.f() & (one.f() - 1);
- uint32_t divisor;
- int divisor_exponent_plus_one;
- BiggestPowerTen(integrals, DiyFp::kSignificandSize - (-one.e()),
- &divisor, &divisor_exponent_plus_one);
- *kappa = divisor_exponent_plus_one;
- *length = 0;
-
- // Loop invariant: buffer = w / 10^kappa (integer division)
- // The invariant holds for the first iteration: kappa has been initialized
- // with the divisor exponent + 1. And the divisor is the biggest power of ten
- // that is smaller than 'integrals'.
- while (*kappa > 0) {
- int digit = integrals / divisor;
- DOUBLE_CONVERSION_ASSERT(digit <= 9);
- buffer[*length] = static_cast<char>('0' + digit);
- (*length)++;
- requested_digits--;
- integrals %= divisor;
- (*kappa)--;
- // Note that kappa now equals the exponent of the divisor and that the
- // invariant thus holds again.
- if (requested_digits == 0) break;
- divisor /= 10;
- }
-
- if (requested_digits == 0) {
- uint64_t rest =
- (static_cast<uint64_t>(integrals) << -one.e()) + fractionals;
- return RoundWeedCounted(buffer, *length, rest,
- static_cast<uint64_t>(divisor) << -one.e(), w_error,
- kappa);
- }
-
- // The integrals have been generated. We are at the point of the decimal
- // separator. In the following loop we simply multiply the remaining digits by
- // 10 and divide by one. We just need to pay attention to multiply associated
- // data (the 'unit'), too.
- // Note that the multiplication by 10 does not overflow, because w.e >= -60
- // and thus one.e >= -60.
- DOUBLE_CONVERSION_ASSERT(one.e() >= -60);
- DOUBLE_CONVERSION_ASSERT(fractionals < one.f());
- DOUBLE_CONVERSION_ASSERT(DOUBLE_CONVERSION_UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF) / 10 >= one.f());
- while (requested_digits > 0 && fractionals > w_error) {
- fractionals *= 10;
- w_error *= 10;
- // Integer division by one.
- int digit = static_cast<int>(fractionals >> -one.e());
- DOUBLE_CONVERSION_ASSERT(digit <= 9);
- buffer[*length] = static_cast<char>('0' + digit);
- (*length)++;
- requested_digits--;
- fractionals &= one.f() - 1; // Modulo by one.
- (*kappa)--;
- }
- if (requested_digits != 0) return false;
- return RoundWeedCounted(buffer, *length, fractionals, one.f(), w_error,
- kappa);
-}
-
-
-// Provides a decimal representation of v.
-// Returns true if it succeeds, otherwise the result cannot be trusted.
-// There will be *length digits inside the buffer (not null-terminated).
-// If the function returns true then
-// v == (double) (buffer * 10^decimal_exponent).
-// The digits in the buffer are the shortest representation possible: no
-// 0.09999999999999999 instead of 0.1. The shorter representation will even be
-// chosen even if the longer one would be closer to v.
-// The last digit will be closest to the actual v. That is, even if several
-// digits might correctly yield 'v' when read again, the closest will be
-// computed.
-static bool Grisu3(double v,
- FastDtoaMode mode,
- Vector<char> buffer,
- int* length,
- int* decimal_exponent) {
- DiyFp w = Double(v).AsNormalizedDiyFp();
- // boundary_minus and boundary_plus are the boundaries between v and its
- // closest floating-point neighbors. Any number strictly between
- // boundary_minus and boundary_plus will round to v when convert to a double.
- // Grisu3 will never output representations that lie exactly on a boundary.
- DiyFp boundary_minus, boundary_plus;
- if (mode == FAST_DTOA_SHORTEST) {
- Double(v).NormalizedBoundaries(&boundary_minus, &boundary_plus);
- } else {
- DOUBLE_CONVERSION_ASSERT(mode == FAST_DTOA_SHORTEST_SINGLE);
- float single_v = static_cast<float>(v);
- Single(single_v).NormalizedBoundaries(&boundary_minus, &boundary_plus);
- }
- DOUBLE_CONVERSION_ASSERT(boundary_plus.e() == w.e());
- DiyFp ten_mk; // Cached power of ten: 10^-k
- int mk; // -k
- int ten_mk_minimal_binary_exponent =
- kMinimalTargetExponent - (w.e() + DiyFp::kSignificandSize);
- int ten_mk_maximal_binary_exponent =
- kMaximalTargetExponent - (w.e() + DiyFp::kSignificandSize);
- PowersOfTenCache::GetCachedPowerForBinaryExponentRange(
- ten_mk_minimal_binary_exponent,
- ten_mk_maximal_binary_exponent,
- &ten_mk, &mk);
- DOUBLE_CONVERSION_ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() +
- DiyFp::kSignificandSize) &&
- (kMaximalTargetExponent >= w.e() + ten_mk.e() +
- DiyFp::kSignificandSize));
- // Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a
- // 64 bit significand and ten_mk is thus only precise up to 64 bits.
-
- // The DiyFp::Times procedure rounds its result, and ten_mk is approximated
- // too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now
- // off by a small amount.
- // In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w.
- // In other words: let f = scaled_w.f() and e = scaled_w.e(), then
- // (f-1) * 2^e < w*10^k < (f+1) * 2^e
- DiyFp scaled_w = DiyFp::Times(w, ten_mk);
- DOUBLE_CONVERSION_ASSERT(scaled_w.e() ==
- boundary_plus.e() + ten_mk.e() + DiyFp::kSignificandSize);
- // In theory it would be possible to avoid some recomputations by computing
- // the difference between w and boundary_minus/plus (a power of 2) and to
- // compute scaled_boundary_minus/plus by subtracting/adding from
- // scaled_w. However the code becomes much less readable and the speed
- // enhancements are not terriffic.
- DiyFp scaled_boundary_minus = DiyFp::Times(boundary_minus, ten_mk);
- DiyFp scaled_boundary_plus = DiyFp::Times(boundary_plus, ten_mk);
-
- // DigitGen will generate the digits of scaled_w. Therefore we have
- // v == (double) (scaled_w * 10^-mk).
- // Set decimal_exponent == -mk and pass it to DigitGen. If scaled_w is not an
- // integer than it will be updated. For instance if scaled_w == 1.23 then
- // the buffer will be filled with "123" und the decimal_exponent will be
- // decreased by 2.
- int kappa;
- bool result = DigitGen(scaled_boundary_minus, scaled_w, scaled_boundary_plus,
- buffer, length, &kappa);
- *decimal_exponent = -mk + kappa;
- return result;
-}
-
-
-// The "counted" version of grisu3 (see above) only generates requested_digits
-// number of digits. This version does not generate the shortest representation,
-// and with enough requested digits 0.1 will at some point print as 0.9999999...
-// Grisu3 is too imprecise for real halfway cases (1.5 will not work) and
-// therefore the rounding strategy for halfway cases is irrelevant.
-static bool Grisu3Counted(double v,
- int requested_digits,
- Vector<char> buffer,
- int* length,
- int* decimal_exponent) {
- DiyFp w = Double(v).AsNormalizedDiyFp();
- DiyFp ten_mk; // Cached power of ten: 10^-k
- int mk; // -k
- int ten_mk_minimal_binary_exponent =
- kMinimalTargetExponent - (w.e() + DiyFp::kSignificandSize);
- int ten_mk_maximal_binary_exponent =
- kMaximalTargetExponent - (w.e() + DiyFp::kSignificandSize);
- PowersOfTenCache::GetCachedPowerForBinaryExponentRange(
- ten_mk_minimal_binary_exponent,
- ten_mk_maximal_binary_exponent,
- &ten_mk, &mk);
- DOUBLE_CONVERSION_ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() +
- DiyFp::kSignificandSize) &&
- (kMaximalTargetExponent >= w.e() + ten_mk.e() +
- DiyFp::kSignificandSize));
- // Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a
- // 64 bit significand and ten_mk is thus only precise up to 64 bits.
-
- // The DiyFp::Times procedure rounds its result, and ten_mk is approximated
- // too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now
- // off by a small amount.
- // In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w.
- // In other words: let f = scaled_w.f() and e = scaled_w.e(), then
- // (f-1) * 2^e < w*10^k < (f+1) * 2^e
- DiyFp scaled_w = DiyFp::Times(w, ten_mk);
-
- // We now have (double) (scaled_w * 10^-mk).
- // DigitGen will generate the first requested_digits digits of scaled_w and
- // return together with a kappa such that scaled_w ~= buffer * 10^kappa. (It
- // will not always be exactly the same since DigitGenCounted only produces a
- // limited number of digits.)
- int kappa;
- bool result = DigitGenCounted(scaled_w, requested_digits,
- buffer, length, &kappa);
- *decimal_exponent = -mk + kappa;
- return result;
-}
-
-
-bool FastDtoa(double v,
- FastDtoaMode mode,
- int requested_digits,
- Vector<char> buffer,
- int* length,
- int* decimal_point) {
- DOUBLE_CONVERSION_ASSERT(v > 0);
- DOUBLE_CONVERSION_ASSERT(!Double(v).IsSpecial());
-
- bool result = false;
- int decimal_exponent = 0;
- switch (mode) {
- case FAST_DTOA_SHORTEST:
- case FAST_DTOA_SHORTEST_SINGLE:
- result = Grisu3(v, mode, buffer, length, &decimal_exponent);
- break;
- case FAST_DTOA_PRECISION:
- result = Grisu3Counted(v, requested_digits,
- buffer, length, &decimal_exponent);
- break;
- default:
- DOUBLE_CONVERSION_UNREACHABLE();
- }
- if (result) {
- *decimal_point = *length + decimal_exponent;
- buffer[*length] = '\0';
- }
- return result;
-}
-
-} // namespace double_conversion
-
-// ICU PATCH: Close ICU namespace
-U_NAMESPACE_END
-#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
+// © 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 2012 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
+
+// ICU PATCH: Customize header file paths for ICU.
+
+#include "double-conversion-fast-dtoa.h"
+
+#include "double-conversion-cached-powers.h"
+#include "double-conversion-diy-fp.h"
+#include "double-conversion-ieee.h"
+
+// ICU PATCH: Wrap in ICU namespace
+U_NAMESPACE_BEGIN
+
+namespace double_conversion {
+
+// The minimal and maximal target exponent define the range of w's binary
+// exponent, where 'w' is the result of multiplying the input by a cached power
+// of ten.
+//
+// A different range might be chosen on a different platform, to optimize digit
+// generation, but a smaller range requires more powers of ten to be cached.
+static const int kMinimalTargetExponent = -60;
+static const int kMaximalTargetExponent = -32;
+
+
+// Adjusts the last digit of the generated number, and screens out generated
+// solutions that may be inaccurate. A solution may be inaccurate if it is
+// outside the safe interval, or if we cannot prove that it is closer to the
+// input than a neighboring representation of the same length.
+//
+// Input: * buffer containing the digits of too_high / 10^kappa
+// * the buffer's length
+// * distance_too_high_w == (too_high - w).f() * unit
+// * unsafe_interval == (too_high - too_low).f() * unit
+// * rest = (too_high - buffer * 10^kappa).f() * unit
+// * ten_kappa = 10^kappa * unit
+// * unit = the common multiplier
+// Output: returns true if the buffer is guaranteed to contain the closest
+// representable number to the input.
+// Modifies the generated digits in the buffer to approach (round towards) w.
+static bool RoundWeed(Vector<char> buffer,
+ int length,
+ uint64_t distance_too_high_w,
+ uint64_t unsafe_interval,
+ uint64_t rest,
+ uint64_t ten_kappa,
+ uint64_t unit) {
+ uint64_t small_distance = distance_too_high_w - unit;
+ uint64_t big_distance = distance_too_high_w + unit;
+ // Let w_low = too_high - big_distance, and
+ // w_high = too_high - small_distance.
+ // Note: w_low < w < w_high
+ //
+ // The real w (* unit) must lie somewhere inside the interval
+ // ]w_low; w_high[ (often written as "(w_low; w_high)")
+
+ // Basically the buffer currently contains a number in the unsafe interval
+ // ]too_low; too_high[ with too_low < w < too_high
+ //
+ // too_high - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ // ^v 1 unit ^ ^ ^ ^
+ // boundary_high --------------------- . . . .
+ // ^v 1 unit . . . .
+ // - - - - - - - - - - - - - - - - - - - + - - + - - - - - - . .
+ // . . ^ . .
+ // . big_distance . . .
+ // . . . . rest
+ // small_distance . . . .
+ // v . . . .
+ // w_high - - - - - - - - - - - - - - - - - - . . . .
+ // ^v 1 unit . . . .
+ // w ---------------------------------------- . . . .
+ // ^v 1 unit v . . .
+ // w_low - - - - - - - - - - - - - - - - - - - - - . . .
+ // . . v
+ // buffer --------------------------------------------------+-------+--------
+ // . .
+ // safe_interval .
+ // v .
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .
+ // ^v 1 unit .
+ // boundary_low ------------------------- unsafe_interval
+ // ^v 1 unit v
+ // too_low - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ //
+ //
+ // Note that the value of buffer could lie anywhere inside the range too_low
+ // to too_high.
+ //
+ // boundary_low, boundary_high and w are approximations of the real boundaries
+ // and v (the input number). They are guaranteed to be precise up to one unit.
+ // In fact the error is guaranteed to be strictly less than one unit.
+ //
+ // Anything that lies outside the unsafe interval is guaranteed not to round
+ // to v when read again.
+ // Anything that lies inside the safe interval is guaranteed to round to v
+ // when read again.
+ // If the number inside the buffer lies inside the unsafe interval but not
+ // inside the safe interval then we simply do not know and bail out (returning
+ // false).
+ //
+ // Similarly we have to take into account the imprecision of 'w' when finding
+ // the closest representation of 'w'. If we have two potential
+ // representations, and one is closer to both w_low and w_high, then we know
+ // it is closer to the actual value v.
+ //
+ // By generating the digits of too_high we got the largest (closest to
+ // too_high) buffer that is still in the unsafe interval. In the case where
+ // w_high < buffer < too_high we try to decrement the buffer.
+ // This way the buffer approaches (rounds towards) w.
+ // There are 3 conditions that stop the decrementation process:
+ // 1) the buffer is already below w_high
+ // 2) decrementing the buffer would make it leave the unsafe interval
+ // 3) decrementing the buffer would yield a number below w_high and farther
+ // away than the current number. In other words:
+ // (buffer{-1} < w_high) && w_high - buffer{-1} > buffer - w_high
+ // Instead of using the buffer directly we use its distance to too_high.
+ // Conceptually rest ~= too_high - buffer
+ // We need to do the following tests in this order to avoid over- and
+ // underflows.
+ DOUBLE_CONVERSION_ASSERT(rest <= unsafe_interval);
+ while (rest < small_distance && // Negated condition 1
+ unsafe_interval - rest >= ten_kappa && // Negated condition 2
+ (rest + ten_kappa < small_distance || // buffer{-1} > w_high
+ small_distance - rest >= rest + ten_kappa - small_distance)) {
+ buffer[length - 1]--;
+ rest += ten_kappa;
+ }
+
+ // We have approached w+ as much as possible. We now test if approaching w-
+ // would require changing the buffer. If yes, then we have two possible
+ // representations close to w, but we cannot decide which one is closer.
+ if (rest < big_distance &&
+ unsafe_interval - rest >= ten_kappa &&
+ (rest + ten_kappa < big_distance ||
+ big_distance - rest > rest + ten_kappa - big_distance)) {
+ return false;
+ }
+
+ // Weeding test.
+ // The safe interval is [too_low + 2 ulp; too_high - 2 ulp]
+ // Since too_low = too_high - unsafe_interval this is equivalent to
+ // [too_high - unsafe_interval + 4 ulp; too_high - 2 ulp]
+ // Conceptually we have: rest ~= too_high - buffer
+ return (2 * unit <= rest) && (rest <= unsafe_interval - 4 * unit);
+}
+
+
+// Rounds the buffer upwards if the result is closer to v by possibly adding
+// 1 to the buffer. If the precision of the calculation is not sufficient to
+// round correctly, return false.
+// The rounding might shift the whole buffer in which case the kappa is
+// adjusted. For example "99", kappa = 3 might become "10", kappa = 4.
+//
+// If 2*rest > ten_kappa then the buffer needs to be round up.
+// rest can have an error of +/- 1 unit. This function accounts for the
+// imprecision and returns false, if the rounding direction cannot be
+// unambiguously determined.
+//
+// Precondition: rest < ten_kappa.
+static bool RoundWeedCounted(Vector<char> buffer,
+ int length,
+ uint64_t rest,
+ uint64_t ten_kappa,
+ uint64_t unit,
+ int* kappa) {
+ DOUBLE_CONVERSION_ASSERT(rest < ten_kappa);
+ // The following tests are done in a specific order to avoid overflows. They
+ // will work correctly with any uint64 values of rest < ten_kappa and unit.
+ //
+ // If the unit is too big, then we don't know which way to round. For example
+ // a unit of 50 means that the real number lies within rest +/- 50. If
+ // 10^kappa == 40 then there is no way to tell which way to round.
+ if (unit >= ten_kappa) return false;
+ // Even if unit is just half the size of 10^kappa we are already completely
+ // lost. (And after the previous test we know that the expression will not
+ // over/underflow.)
+ if (ten_kappa - unit <= unit) return false;
+ // If 2 * (rest + unit) <= 10^kappa we can safely round down.
+ if ((ten_kappa - rest > rest) && (ten_kappa - 2 * rest >= 2 * unit)) {
+ return true;
+ }
+ // If 2 * (rest - unit) >= 10^kappa, then we can safely round up.
+ if ((rest > unit) && (ten_kappa - (rest - unit) <= (rest - unit))) {
+ // Increment the last digit recursively until we find a non '9' digit.
+ buffer[length - 1]++;
+ for (int i = length - 1; i > 0; --i) {
+ if (buffer[i] != '0' + 10) break;
+ buffer[i] = '0';
+ buffer[i - 1]++;
+ }
+ // If the first digit is now '0'+ 10 we had a buffer with all '9's. With the
+ // exception of the first digit all digits are now '0'. Simply switch the
+ // first digit to '1' and adjust the kappa. Example: "99" becomes "10" and
+ // the power (the kappa) is increased.
+ if (buffer[0] == '0' + 10) {
+ buffer[0] = '1';
+ (*kappa) += 1;
+ }
+ return true;
+ }
+ return false;
+}
+
+// Returns the biggest power of ten that is less than or equal to the given
+// number. We furthermore receive the maximum number of bits 'number' has.
+//
+// Returns power == 10^(exponent_plus_one-1) such that
+// power <= number < power * 10.
+// If number_bits == 0 then 0^(0-1) is returned.
+// The number of bits must be <= 32.
+// Precondition: number < (1 << (number_bits + 1)).
+
+// Inspired by the method for finding an integer log base 10 from here:
+// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
+static unsigned int const kSmallPowersOfTen[] =
+ {0, 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000,
+ 1000000000};
+
+static void BiggestPowerTen(uint32_t number,
+ int number_bits,
+ uint32_t* power,
+ int* exponent_plus_one) {
+ DOUBLE_CONVERSION_ASSERT(number < (1u << (number_bits + 1)));
+ // 1233/4096 is approximately 1/lg(10).
+ int exponent_plus_one_guess = ((number_bits + 1) * 1233 >> 12);
+ // We increment to skip over the first entry in the kPowersOf10 table.
+ // Note: kPowersOf10[i] == 10^(i-1).
+ exponent_plus_one_guess++;
+ // We don't have any guarantees that 2^number_bits <= number.
+ if (number < kSmallPowersOfTen[exponent_plus_one_guess]) {
+ exponent_plus_one_guess--;
+ }
+ *power = kSmallPowersOfTen[exponent_plus_one_guess];
+ *exponent_plus_one = exponent_plus_one_guess;
+}
+
+// Generates the digits of input number w.
+// w is a floating-point number (DiyFp), consisting of a significand and an
+// exponent. Its exponent is bounded by kMinimalTargetExponent and
+// kMaximalTargetExponent.
+// Hence -60 <= w.e() <= -32.
+//
+// Returns false if it fails, in which case the generated digits in the buffer
+// should not be used.
+// Preconditions:
+// * low, w and high are correct up to 1 ulp (unit in the last place). That
+// is, their error must be less than a unit of their last digits.
+// * low.e() == w.e() == high.e()
+// * low < w < high, and taking into account their error: low~ <= high~
+// * kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent
+// Postconditions: returns false if procedure fails.
+// otherwise:
+// * buffer is not null-terminated, but len contains the number of digits.
+// * buffer contains the shortest possible decimal digit-sequence
+// such that LOW < buffer * 10^kappa < HIGH, where LOW and HIGH are the
+// correct values of low and high (without their error).
+// * if more than one decimal representation gives the minimal number of
+// decimal digits then the one closest to W (where W is the correct value
+// of w) is chosen.
+// Remark: this procedure takes into account the imprecision of its input
+// numbers. If the precision is not enough to guarantee all the postconditions
+// then false is returned. This usually happens rarely (~0.5%).
+//
+// Say, for the sake of example, that
+// w.e() == -48, and w.f() == 0x1234567890abcdef
+// w's value can be computed by w.f() * 2^w.e()
+// We can obtain w's integral digits by simply shifting w.f() by -w.e().
+// -> w's integral part is 0x1234
+// w's fractional part is therefore 0x567890abcdef.
+// Printing w's integral part is easy (simply print 0x1234 in decimal).
+// In order to print its fraction we repeatedly multiply the fraction by 10 and
+// get each digit. Example the first digit after the point would be computed by
+// (0x567890abcdef * 10) >> 48. -> 3
+// The whole thing becomes slightly more complicated because we want to stop
+// once we have enough digits. That is, once the digits inside the buffer
+// represent 'w' we can stop. Everything inside the interval low - high
+// represents w. However we have to pay attention to low, high and w's
+// imprecision.
+static bool DigitGen(DiyFp low,
+ DiyFp w,
+ DiyFp high,
+ Vector<char> buffer,
+ int* length,
+ int* kappa) {
+ DOUBLE_CONVERSION_ASSERT(low.e() == w.e() && w.e() == high.e());
+ DOUBLE_CONVERSION_ASSERT(low.f() + 1 <= high.f() - 1);
+ DOUBLE_CONVERSION_ASSERT(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent);
+ // low, w and high are imprecise, but by less than one ulp (unit in the last
+ // place).
+ // If we remove (resp. add) 1 ulp from low (resp. high) we are certain that
+ // the new numbers are outside of the interval we want the final
+ // representation to lie in.
+ // Inversely adding (resp. removing) 1 ulp from low (resp. high) would yield
+ // numbers that are certain to lie in the interval. We will use this fact
+ // later on.
+ // We will now start by generating the digits within the uncertain
+ // interval. Later we will weed out representations that lie outside the safe
+ // interval and thus _might_ lie outside the correct interval.
+ uint64_t unit = 1;
+ DiyFp too_low = DiyFp(low.f() - unit, low.e());
+ DiyFp too_high = DiyFp(high.f() + unit, high.e());
+ // too_low and too_high are guaranteed to lie outside the interval we want the
+ // generated number in.
+ DiyFp unsafe_interval = DiyFp::Minus(too_high, too_low);
+ // We now cut the input number into two parts: the integral digits and the
+ // fractionals. We will not write any decimal separator though, but adapt
+ // kappa instead.
+ // Reminder: we are currently computing the digits (stored inside the buffer)
+ // such that: too_low < buffer * 10^kappa < too_high
+ // We use too_high for the digit_generation and stop as soon as possible.
+ // If we stop early we effectively round down.
+ DiyFp one = DiyFp(static_cast<uint64_t>(1) << -w.e(), w.e());
+ // Division by one is a shift.
+ uint32_t integrals = static_cast<uint32_t>(too_high.f() >> -one.e());
+ // Modulo by one is an and.
+ uint64_t fractionals = too_high.f() & (one.f() - 1);
+ uint32_t divisor;
+ int divisor_exponent_plus_one;
+ BiggestPowerTen(integrals, DiyFp::kSignificandSize - (-one.e()),
+ &divisor, &divisor_exponent_plus_one);
+ *kappa = divisor_exponent_plus_one;
+ *length = 0;
+ // Loop invariant: buffer = too_high / 10^kappa (integer division)
+ // The invariant holds for the first iteration: kappa has been initialized
+ // with the divisor exponent + 1. And the divisor is the biggest power of ten
+ // that is smaller than integrals.
+ while (*kappa > 0) {
+ int digit = integrals / divisor;
+ DOUBLE_CONVERSION_ASSERT(digit <= 9);
+ buffer[*length] = static_cast<char>('0' + digit);
+ (*length)++;
+ integrals %= divisor;
+ (*kappa)--;
+ // Note that kappa now equals the exponent of the divisor and that the
+ // invariant thus holds again.
+ uint64_t rest =
+ (static_cast<uint64_t>(integrals) << -one.e()) + fractionals;
+ // Invariant: too_high = buffer * 10^kappa + DiyFp(rest, one.e())
+ // Reminder: unsafe_interval.e() == one.e()
+ if (rest < unsafe_interval.f()) {
+ // Rounding down (by not emitting the remaining digits) yields a number
+ // that lies within the unsafe interval.
+ return RoundWeed(buffer, *length, DiyFp::Minus(too_high, w).f(),
+ unsafe_interval.f(), rest,
+ static_cast<uint64_t>(divisor) << -one.e(), unit);
+ }
+ divisor /= 10;
+ }
+
+ // The integrals have been generated. We are at the point of the decimal
+ // separator. In the following loop we simply multiply the remaining digits by
+ // 10 and divide by one. We just need to pay attention to multiply associated
+ // data (like the interval or 'unit'), too.
+ // Note that the multiplication by 10 does not overflow, because w.e >= -60
+ // and thus one.e >= -60.
+ DOUBLE_CONVERSION_ASSERT(one.e() >= -60);
+ DOUBLE_CONVERSION_ASSERT(fractionals < one.f());
+ DOUBLE_CONVERSION_ASSERT(DOUBLE_CONVERSION_UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF) / 10 >= one.f());
+ for (;;) {
+ fractionals *= 10;
+ unit *= 10;
+ unsafe_interval.set_f(unsafe_interval.f() * 10);
+ // Integer division by one.
+ int digit = static_cast<int>(fractionals >> -one.e());
+ DOUBLE_CONVERSION_ASSERT(digit <= 9);
+ buffer[*length] = static_cast<char>('0' + digit);
+ (*length)++;
+ fractionals &= one.f() - 1; // Modulo by one.
+ (*kappa)--;
+ if (fractionals < unsafe_interval.f()) {
+ return RoundWeed(buffer, *length, DiyFp::Minus(too_high, w).f() * unit,
+ unsafe_interval.f(), fractionals, one.f(), unit);
+ }
+ }
+}
+
+
+
+// Generates (at most) requested_digits digits of input number w.
+// w is a floating-point number (DiyFp), consisting of a significand and an
+// exponent. Its exponent is bounded by kMinimalTargetExponent and
+// kMaximalTargetExponent.
+// Hence -60 <= w.e() <= -32.
+//
+// Returns false if it fails, in which case the generated digits in the buffer
+// should not be used.
+// Preconditions:
+// * w is correct up to 1 ulp (unit in the last place). That
+// is, its error must be strictly less than a unit of its last digit.
+// * kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent
+//
+// Postconditions: returns false if procedure fails.
+// otherwise:
+// * buffer is not null-terminated, but length contains the number of
+// digits.
+// * the representation in buffer is the most precise representation of
+// requested_digits digits.
+// * buffer contains at most requested_digits digits of w. If there are less
+// than requested_digits digits then some trailing '0's have been removed.
+// * kappa is such that
+// w = buffer * 10^kappa + eps with |eps| < 10^kappa / 2.
+//
+// Remark: This procedure takes into account the imprecision of its input
+// numbers. If the precision is not enough to guarantee all the postconditions
+// then false is returned. This usually happens rarely, but the failure-rate
+// increases with higher requested_digits.
+static bool DigitGenCounted(DiyFp w,
+ int requested_digits,
+ Vector<char> buffer,
+ int* length,
+ int* kappa) {
+ DOUBLE_CONVERSION_ASSERT(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent);
+ DOUBLE_CONVERSION_ASSERT(kMinimalTargetExponent >= -60);
+ DOUBLE_CONVERSION_ASSERT(kMaximalTargetExponent <= -32);
+ // w is assumed to have an error less than 1 unit. Whenever w is scaled we
+ // also scale its error.
+ uint64_t w_error = 1;
+ // We cut the input number into two parts: the integral digits and the
+ // fractional digits. We don't emit any decimal separator, but adapt kappa
+ // instead. Example: instead of writing "1.2" we put "12" into the buffer and
+ // increase kappa by 1.
+ DiyFp one = DiyFp(static_cast<uint64_t>(1) << -w.e(), w.e());
+ // Division by one is a shift.
+ uint32_t integrals = static_cast<uint32_t>(w.f() >> -one.e());
+ // Modulo by one is an and.
+ uint64_t fractionals = w.f() & (one.f() - 1);
+ uint32_t divisor;
+ int divisor_exponent_plus_one;
+ BiggestPowerTen(integrals, DiyFp::kSignificandSize - (-one.e()),
+ &divisor, &divisor_exponent_plus_one);
+ *kappa = divisor_exponent_plus_one;
+ *length = 0;
+
+ // Loop invariant: buffer = w / 10^kappa (integer division)
+ // The invariant holds for the first iteration: kappa has been initialized
+ // with the divisor exponent + 1. And the divisor is the biggest power of ten
+ // that is smaller than 'integrals'.
+ while (*kappa > 0) {
+ int digit = integrals / divisor;
+ DOUBLE_CONVERSION_ASSERT(digit <= 9);
+ buffer[*length] = static_cast<char>('0' + digit);
+ (*length)++;
+ requested_digits--;
+ integrals %= divisor;
+ (*kappa)--;
+ // Note that kappa now equals the exponent of the divisor and that the
+ // invariant thus holds again.
+ if (requested_digits == 0) break;
+ divisor /= 10;
+ }
+
+ if (requested_digits == 0) {
+ uint64_t rest =
+ (static_cast<uint64_t>(integrals) << -one.e()) + fractionals;
+ return RoundWeedCounted(buffer, *length, rest,
+ static_cast<uint64_t>(divisor) << -one.e(), w_error,
+ kappa);
+ }
+
+ // The integrals have been generated. We are at the point of the decimal
+ // separator. In the following loop we simply multiply the remaining digits by
+ // 10 and divide by one. We just need to pay attention to multiply associated
+ // data (the 'unit'), too.
+ // Note that the multiplication by 10 does not overflow, because w.e >= -60
+ // and thus one.e >= -60.
+ DOUBLE_CONVERSION_ASSERT(one.e() >= -60);
+ DOUBLE_CONVERSION_ASSERT(fractionals < one.f());
+ DOUBLE_CONVERSION_ASSERT(DOUBLE_CONVERSION_UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF) / 10 >= one.f());
+ while (requested_digits > 0 && fractionals > w_error) {
+ fractionals *= 10;
+ w_error *= 10;
+ // Integer division by one.
+ int digit = static_cast<int>(fractionals >> -one.e());
+ DOUBLE_CONVERSION_ASSERT(digit <= 9);
+ buffer[*length] = static_cast<char>('0' + digit);
+ (*length)++;
+ requested_digits--;
+ fractionals &= one.f() - 1; // Modulo by one.
+ (*kappa)--;
+ }
+ if (requested_digits != 0) return false;
+ return RoundWeedCounted(buffer, *length, fractionals, one.f(), w_error,
+ kappa);
+}
+
+
+// Provides a decimal representation of v.
+// Returns true if it succeeds, otherwise the result cannot be trusted.
+// There will be *length digits inside the buffer (not null-terminated).
+// If the function returns true then
+// v == (double) (buffer * 10^decimal_exponent).
+// The digits in the buffer are the shortest representation possible: no
+// 0.09999999999999999 instead of 0.1. The shorter representation will even be
+// chosen even if the longer one would be closer to v.
+// The last digit will be closest to the actual v. That is, even if several
+// digits might correctly yield 'v' when read again, the closest will be
+// computed.
+static bool Grisu3(double v,
+ FastDtoaMode mode,
+ Vector<char> buffer,
+ int* length,
+ int* decimal_exponent) {
+ DiyFp w = Double(v).AsNormalizedDiyFp();
+ // boundary_minus and boundary_plus are the boundaries between v and its
+ // closest floating-point neighbors. Any number strictly between
+ // boundary_minus and boundary_plus will round to v when convert to a double.
+ // Grisu3 will never output representations that lie exactly on a boundary.
+ DiyFp boundary_minus, boundary_plus;
+ if (mode == FAST_DTOA_SHORTEST) {
+ Double(v).NormalizedBoundaries(&boundary_minus, &boundary_plus);
+ } else {
+ DOUBLE_CONVERSION_ASSERT(mode == FAST_DTOA_SHORTEST_SINGLE);
+ float single_v = static_cast<float>(v);
+ Single(single_v).NormalizedBoundaries(&boundary_minus, &boundary_plus);
+ }
+ DOUBLE_CONVERSION_ASSERT(boundary_plus.e() == w.e());
+ DiyFp ten_mk; // Cached power of ten: 10^-k
+ int mk; // -k
+ int ten_mk_minimal_binary_exponent =
+ kMinimalTargetExponent - (w.e() + DiyFp::kSignificandSize);
+ int ten_mk_maximal_binary_exponent =
+ kMaximalTargetExponent - (w.e() + DiyFp::kSignificandSize);
+ PowersOfTenCache::GetCachedPowerForBinaryExponentRange(
+ ten_mk_minimal_binary_exponent,
+ ten_mk_maximal_binary_exponent,
+ &ten_mk, &mk);
+ DOUBLE_CONVERSION_ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() +
+ DiyFp::kSignificandSize) &&
+ (kMaximalTargetExponent >= w.e() + ten_mk.e() +
+ DiyFp::kSignificandSize));
+ // Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a
+ // 64 bit significand and ten_mk is thus only precise up to 64 bits.
+
+ // The DiyFp::Times procedure rounds its result, and ten_mk is approximated
+ // too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now
+ // off by a small amount.
+ // In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w.
+ // In other words: let f = scaled_w.f() and e = scaled_w.e(), then
+ // (f-1) * 2^e < w*10^k < (f+1) * 2^e
+ DiyFp scaled_w = DiyFp::Times(w, ten_mk);
+ DOUBLE_CONVERSION_ASSERT(scaled_w.e() ==
+ boundary_plus.e() + ten_mk.e() + DiyFp::kSignificandSize);
+ // In theory it would be possible to avoid some recomputations by computing
+ // the difference between w and boundary_minus/plus (a power of 2) and to
+ // compute scaled_boundary_minus/plus by subtracting/adding from
+ // scaled_w. However the code becomes much less readable and the speed
+ // enhancements are not terriffic.
+ DiyFp scaled_boundary_minus = DiyFp::Times(boundary_minus, ten_mk);
+ DiyFp scaled_boundary_plus = DiyFp::Times(boundary_plus, ten_mk);
+
+ // DigitGen will generate the digits of scaled_w. Therefore we have
+ // v == (double) (scaled_w * 10^-mk).
+ // Set decimal_exponent == -mk and pass it to DigitGen. If scaled_w is not an
+ // integer than it will be updated. For instance if scaled_w == 1.23 then
+ // the buffer will be filled with "123" und the decimal_exponent will be
+ // decreased by 2.
+ int kappa;
+ bool result = DigitGen(scaled_boundary_minus, scaled_w, scaled_boundary_plus,
+ buffer, length, &kappa);
+ *decimal_exponent = -mk + kappa;
+ return result;
+}
+
+
+// The "counted" version of grisu3 (see above) only generates requested_digits
+// number of digits. This version does not generate the shortest representation,
+// and with enough requested digits 0.1 will at some point print as 0.9999999...
+// Grisu3 is too imprecise for real halfway cases (1.5 will not work) and
+// therefore the rounding strategy for halfway cases is irrelevant.
+static bool Grisu3Counted(double v,
+ int requested_digits,
+ Vector<char> buffer,
+ int* length,
+ int* decimal_exponent) {
+ DiyFp w = Double(v).AsNormalizedDiyFp();
+ DiyFp ten_mk; // Cached power of ten: 10^-k
+ int mk; // -k
+ int ten_mk_minimal_binary_exponent =
+ kMinimalTargetExponent - (w.e() + DiyFp::kSignificandSize);
+ int ten_mk_maximal_binary_exponent =
+ kMaximalTargetExponent - (w.e() + DiyFp::kSignificandSize);
+ PowersOfTenCache::GetCachedPowerForBinaryExponentRange(
+ ten_mk_minimal_binary_exponent,
+ ten_mk_maximal_binary_exponent,
+ &ten_mk, &mk);
+ DOUBLE_CONVERSION_ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() +
+ DiyFp::kSignificandSize) &&
+ (kMaximalTargetExponent >= w.e() + ten_mk.e() +
+ DiyFp::kSignificandSize));
+ // Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a
+ // 64 bit significand and ten_mk is thus only precise up to 64 bits.
+
+ // The DiyFp::Times procedure rounds its result, and ten_mk is approximated
+ // too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now
+ // off by a small amount.
+ // In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w.
+ // In other words: let f = scaled_w.f() and e = scaled_w.e(), then
+ // (f-1) * 2^e < w*10^k < (f+1) * 2^e
+ DiyFp scaled_w = DiyFp::Times(w, ten_mk);
+
+ // We now have (double) (scaled_w * 10^-mk).
+ // DigitGen will generate the first requested_digits digits of scaled_w and
+ // return together with a kappa such that scaled_w ~= buffer * 10^kappa. (It
+ // will not always be exactly the same since DigitGenCounted only produces a
+ // limited number of digits.)
+ int kappa;
+ bool result = DigitGenCounted(scaled_w, requested_digits,
+ buffer, length, &kappa);
+ *decimal_exponent = -mk + kappa;
+ return result;
+}
+
+
+bool FastDtoa(double v,
+ FastDtoaMode mode,
+ int requested_digits,
+ Vector<char> buffer,
+ int* length,
+ int* decimal_point) {
+ DOUBLE_CONVERSION_ASSERT(v > 0);
+ DOUBLE_CONVERSION_ASSERT(!Double(v).IsSpecial());
+
+ bool result = false;
+ int decimal_exponent = 0;
+ switch (mode) {
+ case FAST_DTOA_SHORTEST:
+ case FAST_DTOA_SHORTEST_SINGLE:
+ result = Grisu3(v, mode, buffer, length, &decimal_exponent);
+ break;
+ case FAST_DTOA_PRECISION:
+ result = Grisu3Counted(v, requested_digits,
+ buffer, length, &decimal_exponent);
+ break;
+ default:
+ DOUBLE_CONVERSION_UNREACHABLE();
+ }
+ if (result) {
+ *decimal_point = *length + decimal_exponent;
+ buffer[*length] = '\0';
+ }
+ return result;
+}
+
+} // namespace double_conversion
+
+// ICU PATCH: Close ICU namespace
+U_NAMESPACE_END
+#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
diff --git a/contrib/libs/icu/i18n/double-conversion-fast-dtoa.h b/contrib/libs/icu/i18n/double-conversion-fast-dtoa.h
index 58a6470052..f751f1122e 100644
--- a/contrib/libs/icu/i18n/double-conversion-fast-dtoa.h
+++ b/contrib/libs/icu/i18n/double-conversion-fast-dtoa.h
@@ -1,106 +1,106 @@
-// © 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_FAST_DTOA_H_
-#define DOUBLE_CONVERSION_FAST_DTOA_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 {
-
-enum FastDtoaMode {
- // Computes the shortest representation of the given input. The returned
- // result will be the most accurate number of this length. Longer
- // representations might be more accurate.
- FAST_DTOA_SHORTEST,
- // Same as FAST_DTOA_SHORTEST but for single-precision floats.
- FAST_DTOA_SHORTEST_SINGLE,
- // Computes a representation where the precision (number of digits) is
- // given as input. The precision is independent of the decimal point.
- FAST_DTOA_PRECISION
-};
-
-// FastDtoa will produce at most kFastDtoaMaximalLength digits. This does not
-// include the terminating '\0' character.
-static const int kFastDtoaMaximalLength = 17;
-// Same for single-precision numbers.
-static const int kFastDtoaMaximalSingleLength = 9;
-
-// Provides a decimal representation of v.
-// The result should be interpreted as buffer * 10^(point - length).
-//
-// Precondition:
-// * v must be a strictly positive finite double.
-//
-// Returns true if it succeeds, otherwise the result can not be trusted.
-// There will be *length digits inside the buffer followed by a null terminator.
-// If the function returns true and mode equals
-// - FAST_DTOA_SHORTEST, then
-// the parameter requested_digits is ignored.
-// The result satisfies
-// v == (double) (buffer * 10^(point - length)).
-// The digits in the buffer are the shortest representation possible. E.g.
-// if 0.099999999999 and 0.1 represent the same double then "1" is returned
-// with point = 0.
-// The last digit will be closest to the actual v. That is, even if several
-// digits might correctly yield 'v' when read again, the buffer will contain
-// the one closest to v.
-// - FAST_DTOA_PRECISION, then
-// the buffer contains requested_digits digits.
-// the difference v - (buffer * 10^(point-length)) is closest to zero for
-// all possible representations of requested_digits digits.
-// If there are two values that are equally close, then FastDtoa returns
-// false.
-// For both modes the buffer must be large enough to hold the result.
-bool FastDtoa(double d,
- FastDtoaMode mode,
- int requested_digits,
- Vector<char> buffer,
- int* length,
- int* decimal_point);
-
-} // namespace double_conversion
-
-// ICU PATCH: Close ICU namespace
-U_NAMESPACE_END
-
-#endif // DOUBLE_CONVERSION_FAST_DTOA_H_
-#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
+// © 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_FAST_DTOA_H_
+#define DOUBLE_CONVERSION_FAST_DTOA_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 {
+
+enum FastDtoaMode {
+ // Computes the shortest representation of the given input. The returned
+ // result will be the most accurate number of this length. Longer
+ // representations might be more accurate.
+ FAST_DTOA_SHORTEST,
+ // Same as FAST_DTOA_SHORTEST but for single-precision floats.
+ FAST_DTOA_SHORTEST_SINGLE,
+ // Computes a representation where the precision (number of digits) is
+ // given as input. The precision is independent of the decimal point.
+ FAST_DTOA_PRECISION
+};
+
+// FastDtoa will produce at most kFastDtoaMaximalLength digits. This does not
+// include the terminating '\0' character.
+static const int kFastDtoaMaximalLength = 17;
+// Same for single-precision numbers.
+static const int kFastDtoaMaximalSingleLength = 9;
+
+// Provides a decimal representation of v.
+// The result should be interpreted as buffer * 10^(point - length).
+//
+// Precondition:
+// * v must be a strictly positive finite double.
+//
+// Returns true if it succeeds, otherwise the result can not be trusted.
+// There will be *length digits inside the buffer followed by a null terminator.
+// If the function returns true and mode equals
+// - FAST_DTOA_SHORTEST, then
+// the parameter requested_digits is ignored.
+// The result satisfies
+// v == (double) (buffer * 10^(point - length)).
+// The digits in the buffer are the shortest representation possible. E.g.
+// if 0.099999999999 and 0.1 represent the same double then "1" is returned
+// with point = 0.
+// The last digit will be closest to the actual v. That is, even if several
+// digits might correctly yield 'v' when read again, the buffer will contain
+// the one closest to v.
+// - FAST_DTOA_PRECISION, then
+// the buffer contains requested_digits digits.
+// the difference v - (buffer * 10^(point-length)) is closest to zero for
+// all possible representations of requested_digits digits.
+// If there are two values that are equally close, then FastDtoa returns
+// false.
+// For both modes the buffer must be large enough to hold the result.
+bool FastDtoa(double d,
+ FastDtoaMode mode,
+ int requested_digits,
+ Vector<char> buffer,
+ int* length,
+ int* decimal_point);
+
+} // namespace double_conversion
+
+// ICU PATCH: Close ICU namespace
+U_NAMESPACE_END
+
+#endif // DOUBLE_CONVERSION_FAST_DTOA_H_
+#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
diff --git a/contrib/libs/icu/i18n/double-conversion-ieee.h b/contrib/libs/icu/i18n/double-conversion-ieee.h
index 31c35867de..8cfe2e755a 100644
--- a/contrib/libs/icu/i18n/double-conversion-ieee.h
+++ b/contrib/libs/icu/i18n/double-conversion-ieee.h
@@ -1,440 +1,440 @@
-// © 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 2012 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_DOUBLE_H_
-#define DOUBLE_CONVERSION_DOUBLE_H_
-
-// ICU PATCH: Customize header file paths for ICU.
-
-#include "double-conversion-diy-fp.h"
-
-// ICU PATCH: Wrap in ICU namespace
-U_NAMESPACE_BEGIN
-
-namespace double_conversion {
-
-// We assume that doubles and uint64_t have the same endianness.
-static uint64_t double_to_uint64(double d) { return BitCast<uint64_t>(d); }
-static double uint64_to_double(uint64_t d64) { return BitCast<double>(d64); }
-static uint32_t float_to_uint32(float f) { return BitCast<uint32_t>(f); }
-static float uint32_to_float(uint32_t d32) { return BitCast<float>(d32); }
-
-// Helper functions for doubles.
-class Double {
- public:
- static const uint64_t kSignMask = DOUBLE_CONVERSION_UINT64_2PART_C(0x80000000, 00000000);
- static const uint64_t kExponentMask = DOUBLE_CONVERSION_UINT64_2PART_C(0x7FF00000, 00000000);
- static const uint64_t kSignificandMask = DOUBLE_CONVERSION_UINT64_2PART_C(0x000FFFFF, FFFFFFFF);
- static const uint64_t kHiddenBit = DOUBLE_CONVERSION_UINT64_2PART_C(0x00100000, 00000000);
- static const uint64_t kQuietNanBit = DOUBLE_CONVERSION_UINT64_2PART_C(0x00080000, 00000000);
- static const int kPhysicalSignificandSize = 52; // Excludes the hidden bit.
- static const int kSignificandSize = 53;
- static const int kExponentBias = 0x3FF + kPhysicalSignificandSize;
- static const int kMaxExponent = 0x7FF - kExponentBias;
-
- Double() : d64_(0) {}
- explicit Double(double d) : d64_(double_to_uint64(d)) {}
- explicit Double(uint64_t d64) : d64_(d64) {}
- explicit Double(DiyFp diy_fp)
- : d64_(DiyFpToUint64(diy_fp)) {}
-
- // The value encoded by this Double must be greater or equal to +0.0.
- // It must not be special (infinity, or NaN).
- DiyFp AsDiyFp() const {
- DOUBLE_CONVERSION_ASSERT(Sign() > 0);
- DOUBLE_CONVERSION_ASSERT(!IsSpecial());
- return DiyFp(Significand(), Exponent());
- }
-
- // The value encoded by this Double must be strictly greater than 0.
- DiyFp AsNormalizedDiyFp() const {
- DOUBLE_CONVERSION_ASSERT(value() > 0.0);
- uint64_t f = Significand();
- int e = Exponent();
-
- // The current double could be a denormal.
- while ((f & kHiddenBit) == 0) {
- f <<= 1;
- e--;
- }
- // Do the final shifts in one go.
- f <<= DiyFp::kSignificandSize - kSignificandSize;
- e -= DiyFp::kSignificandSize - kSignificandSize;
- return DiyFp(f, e);
- }
-
- // Returns the double's bit as uint64.
- uint64_t AsUint64() const {
- return d64_;
- }
-
- // Returns the next greater double. Returns +infinity on input +infinity.
- double NextDouble() const {
- if (d64_ == kInfinity) return Double(kInfinity).value();
- if (Sign() < 0 && Significand() == 0) {
- // -0.0
- return 0.0;
- }
- if (Sign() < 0) {
- return Double(d64_ - 1).value();
- } else {
- return Double(d64_ + 1).value();
- }
- }
-
- double PreviousDouble() const {
- if (d64_ == (kInfinity | kSignMask)) return -Infinity();
- if (Sign() < 0) {
- return Double(d64_ + 1).value();
- } else {
- if (Significand() == 0) return -0.0;
- return Double(d64_ - 1).value();
- }
- }
-
- int Exponent() const {
- if (IsDenormal()) return kDenormalExponent;
-
- uint64_t d64 = AsUint64();
- int biased_e =
- static_cast<int>((d64 & kExponentMask) >> kPhysicalSignificandSize);
- return biased_e - kExponentBias;
- }
-
- uint64_t Significand() const {
- uint64_t d64 = AsUint64();
- uint64_t significand = d64 & kSignificandMask;
- if (!IsDenormal()) {
- return significand + kHiddenBit;
- } else {
- return significand;
- }
- }
-
- // Returns true if the double is a denormal.
- bool IsDenormal() const {
- uint64_t d64 = AsUint64();
- return (d64 & kExponentMask) == 0;
- }
-
- // We consider denormals not to be special.
- // Hence only Infinity and NaN are special.
- bool IsSpecial() const {
- uint64_t d64 = AsUint64();
- return (d64 & kExponentMask) == kExponentMask;
- }
-
- bool IsNan() const {
- uint64_t d64 = AsUint64();
- return ((d64 & kExponentMask) == kExponentMask) &&
- ((d64 & kSignificandMask) != 0);
- }
-
- bool IsQuietNan() const {
- return IsNan() && ((AsUint64() & kQuietNanBit) != 0);
- }
-
- bool IsSignalingNan() const {
- return IsNan() && ((AsUint64() & kQuietNanBit) == 0);
- }
-
-
- bool IsInfinite() const {
- uint64_t d64 = AsUint64();
- return ((d64 & kExponentMask) == kExponentMask) &&
- ((d64 & kSignificandMask) == 0);
- }
-
- int Sign() const {
- uint64_t d64 = AsUint64();
- return (d64 & kSignMask) == 0? 1: -1;
- }
-
- // Precondition: the value encoded by this Double must be greater or equal
- // than +0.0.
- DiyFp UpperBoundary() const {
- DOUBLE_CONVERSION_ASSERT(Sign() > 0);
- return DiyFp(Significand() * 2 + 1, Exponent() - 1);
- }
-
- // Computes the two boundaries of this.
- // The bigger boundary (m_plus) is normalized. The lower boundary has the same
- // exponent as m_plus.
- // Precondition: the value encoded by this Double must be greater than 0.
- void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const {
- DOUBLE_CONVERSION_ASSERT(value() > 0.0);
- DiyFp v = this->AsDiyFp();
- DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1));
- DiyFp m_minus;
- if (LowerBoundaryIsCloser()) {
- m_minus = DiyFp((v.f() << 2) - 1, v.e() - 2);
- } else {
- m_minus = DiyFp((v.f() << 1) - 1, v.e() - 1);
- }
- m_minus.set_f(m_minus.f() << (m_minus.e() - m_plus.e()));
- m_minus.set_e(m_plus.e());
- *out_m_plus = m_plus;
- *out_m_minus = m_minus;
- }
-
- bool LowerBoundaryIsCloser() const {
- // The boundary is closer if the significand is of the form f == 2^p-1 then
- // the lower boundary is closer.
- // Think of v = 1000e10 and v- = 9999e9.
- // Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but
- // at a distance of 1e8.
- // The only exception is for the smallest normal: the largest denormal is
- // at the same distance as its successor.
- // Note: denormals have the same exponent as the smallest normals.
- bool physical_significand_is_zero = ((AsUint64() & kSignificandMask) == 0);
- return physical_significand_is_zero && (Exponent() != kDenormalExponent);
- }
-
- double value() const { return uint64_to_double(d64_); }
-
- // Returns the significand size for a given order of magnitude.
- // If v = f*2^e with 2^p-1 <= f <= 2^p then p+e is v's order of magnitude.
- // This function returns the number of significant binary digits v will have
- // once it's encoded into a double. In almost all cases this is equal to
- // kSignificandSize. The only exceptions are denormals. They start with
- // leading zeroes and their effective significand-size is hence smaller.
- static int SignificandSizeForOrderOfMagnitude(int order) {
- if (order >= (kDenormalExponent + kSignificandSize)) {
- return kSignificandSize;
- }
- if (order <= kDenormalExponent) return 0;
- return order - kDenormalExponent;
- }
-
- static double Infinity() {
- return Double(kInfinity).value();
- }
-
- static double NaN() {
- return Double(kNaN).value();
- }
-
- private:
- static const int kDenormalExponent = -kExponentBias + 1;
- static const uint64_t kInfinity = DOUBLE_CONVERSION_UINT64_2PART_C(0x7FF00000, 00000000);
- static const uint64_t kNaN = DOUBLE_CONVERSION_UINT64_2PART_C(0x7FF80000, 00000000);
-
- const uint64_t d64_;
-
- static uint64_t DiyFpToUint64(DiyFp diy_fp) {
- uint64_t significand = diy_fp.f();
- int exponent = diy_fp.e();
- while (significand > kHiddenBit + kSignificandMask) {
- significand >>= 1;
- exponent++;
- }
- if (exponent >= kMaxExponent) {
- return kInfinity;
- }
- if (exponent < kDenormalExponent) {
- return 0;
- }
- while (exponent > kDenormalExponent && (significand & kHiddenBit) == 0) {
- significand <<= 1;
- exponent--;
- }
- uint64_t biased_exponent;
- if (exponent == kDenormalExponent && (significand & kHiddenBit) == 0) {
- biased_exponent = 0;
- } else {
- biased_exponent = static_cast<uint64_t>(exponent + kExponentBias);
- }
- return (significand & kSignificandMask) |
- (biased_exponent << kPhysicalSignificandSize);
- }
-
- DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN(Double);
-};
-
-class Single {
- public:
- static const uint32_t kSignMask = 0x80000000;
- static const uint32_t kExponentMask = 0x7F800000;
- static const uint32_t kSignificandMask = 0x007FFFFF;
- static const uint32_t kHiddenBit = 0x00800000;
- static const uint32_t kQuietNanBit = 0x00400000;
- static const int kPhysicalSignificandSize = 23; // Excludes the hidden bit.
- static const int kSignificandSize = 24;
-
- Single() : d32_(0) {}
- explicit Single(float f) : d32_(float_to_uint32(f)) {}
- explicit Single(uint32_t d32) : d32_(d32) {}
-
- // The value encoded by this Single must be greater or equal to +0.0.
- // It must not be special (infinity, or NaN).
- DiyFp AsDiyFp() const {
- DOUBLE_CONVERSION_ASSERT(Sign() > 0);
- DOUBLE_CONVERSION_ASSERT(!IsSpecial());
- return DiyFp(Significand(), Exponent());
- }
-
- // Returns the single's bit as uint64.
- uint32_t AsUint32() const {
- return d32_;
- }
-
- int Exponent() const {
- if (IsDenormal()) return kDenormalExponent;
-
- uint32_t d32 = AsUint32();
- int biased_e =
- static_cast<int>((d32 & kExponentMask) >> kPhysicalSignificandSize);
- return biased_e - kExponentBias;
- }
-
- uint32_t Significand() const {
- uint32_t d32 = AsUint32();
- uint32_t significand = d32 & kSignificandMask;
- if (!IsDenormal()) {
- return significand + kHiddenBit;
- } else {
- return significand;
- }
- }
-
- // Returns true if the single is a denormal.
- bool IsDenormal() const {
- uint32_t d32 = AsUint32();
- return (d32 & kExponentMask) == 0;
- }
-
- // We consider denormals not to be special.
- // Hence only Infinity and NaN are special.
- bool IsSpecial() const {
- uint32_t d32 = AsUint32();
- return (d32 & kExponentMask) == kExponentMask;
- }
-
- bool IsNan() const {
- uint32_t d32 = AsUint32();
- return ((d32 & kExponentMask) == kExponentMask) &&
- ((d32 & kSignificandMask) != 0);
- }
-
- bool IsQuietNan() const {
- return IsNan() && ((AsUint32() & kQuietNanBit) != 0);
- }
-
- bool IsSignalingNan() const {
- return IsNan() && ((AsUint32() & kQuietNanBit) == 0);
- }
-
-
- bool IsInfinite() const {
- uint32_t d32 = AsUint32();
- return ((d32 & kExponentMask) == kExponentMask) &&
- ((d32 & kSignificandMask) == 0);
- }
-
- int Sign() const {
- uint32_t d32 = AsUint32();
- return (d32 & kSignMask) == 0? 1: -1;
- }
-
- // Computes the two boundaries of this.
- // The bigger boundary (m_plus) is normalized. The lower boundary has the same
- // exponent as m_plus.
- // Precondition: the value encoded by this Single must be greater than 0.
- void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const {
- DOUBLE_CONVERSION_ASSERT(value() > 0.0);
- DiyFp v = this->AsDiyFp();
- DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1));
- DiyFp m_minus;
- if (LowerBoundaryIsCloser()) {
- m_minus = DiyFp((v.f() << 2) - 1, v.e() - 2);
- } else {
- m_minus = DiyFp((v.f() << 1) - 1, v.e() - 1);
- }
- m_minus.set_f(m_minus.f() << (m_minus.e() - m_plus.e()));
- m_minus.set_e(m_plus.e());
- *out_m_plus = m_plus;
- *out_m_minus = m_minus;
- }
-
- // Precondition: the value encoded by this Single must be greater or equal
- // than +0.0.
- DiyFp UpperBoundary() const {
- DOUBLE_CONVERSION_ASSERT(Sign() > 0);
- return DiyFp(Significand() * 2 + 1, Exponent() - 1);
- }
-
- bool LowerBoundaryIsCloser() const {
- // The boundary is closer if the significand is of the form f == 2^p-1 then
- // the lower boundary is closer.
- // Think of v = 1000e10 and v- = 9999e9.
- // Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but
- // at a distance of 1e8.
- // The only exception is for the smallest normal: the largest denormal is
- // at the same distance as its successor.
- // Note: denormals have the same exponent as the smallest normals.
- bool physical_significand_is_zero = ((AsUint32() & kSignificandMask) == 0);
- return physical_significand_is_zero && (Exponent() != kDenormalExponent);
- }
-
- float value() const { return uint32_to_float(d32_); }
-
- static float Infinity() {
- return Single(kInfinity).value();
- }
-
- static float NaN() {
- return Single(kNaN).value();
- }
-
- private:
- static const int kExponentBias = 0x7F + kPhysicalSignificandSize;
- static const int kDenormalExponent = -kExponentBias + 1;
- static const int kMaxExponent = 0xFF - kExponentBias;
- static const uint32_t kInfinity = 0x7F800000;
- static const uint32_t kNaN = 0x7FC00000;
-
- const uint32_t d32_;
-
- DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN(Single);
-};
-
-} // namespace double_conversion
-
-// ICU PATCH: Close ICU namespace
-U_NAMESPACE_END
-
-#endif // DOUBLE_CONVERSION_DOUBLE_H_
-#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
+// © 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 2012 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_DOUBLE_H_
+#define DOUBLE_CONVERSION_DOUBLE_H_
+
+// ICU PATCH: Customize header file paths for ICU.
+
+#include "double-conversion-diy-fp.h"
+
+// ICU PATCH: Wrap in ICU namespace
+U_NAMESPACE_BEGIN
+
+namespace double_conversion {
+
+// We assume that doubles and uint64_t have the same endianness.
+static uint64_t double_to_uint64(double d) { return BitCast<uint64_t>(d); }
+static double uint64_to_double(uint64_t d64) { return BitCast<double>(d64); }
+static uint32_t float_to_uint32(float f) { return BitCast<uint32_t>(f); }
+static float uint32_to_float(uint32_t d32) { return BitCast<float>(d32); }
+
+// Helper functions for doubles.
+class Double {
+ public:
+ static const uint64_t kSignMask = DOUBLE_CONVERSION_UINT64_2PART_C(0x80000000, 00000000);
+ static const uint64_t kExponentMask = DOUBLE_CONVERSION_UINT64_2PART_C(0x7FF00000, 00000000);
+ static const uint64_t kSignificandMask = DOUBLE_CONVERSION_UINT64_2PART_C(0x000FFFFF, FFFFFFFF);
+ static const uint64_t kHiddenBit = DOUBLE_CONVERSION_UINT64_2PART_C(0x00100000, 00000000);
+ static const uint64_t kQuietNanBit = DOUBLE_CONVERSION_UINT64_2PART_C(0x00080000, 00000000);
+ static const int kPhysicalSignificandSize = 52; // Excludes the hidden bit.
+ static const int kSignificandSize = 53;
+ static const int kExponentBias = 0x3FF + kPhysicalSignificandSize;
+ static const int kMaxExponent = 0x7FF - kExponentBias;
+
+ Double() : d64_(0) {}
+ explicit Double(double d) : d64_(double_to_uint64(d)) {}
+ explicit Double(uint64_t d64) : d64_(d64) {}
+ explicit Double(DiyFp diy_fp)
+ : d64_(DiyFpToUint64(diy_fp)) {}
+
+ // The value encoded by this Double must be greater or equal to +0.0.
+ // It must not be special (infinity, or NaN).
+ DiyFp AsDiyFp() const {
+ DOUBLE_CONVERSION_ASSERT(Sign() > 0);
+ DOUBLE_CONVERSION_ASSERT(!IsSpecial());
+ return DiyFp(Significand(), Exponent());
+ }
+
+ // The value encoded by this Double must be strictly greater than 0.
+ DiyFp AsNormalizedDiyFp() const {
+ DOUBLE_CONVERSION_ASSERT(value() > 0.0);
+ uint64_t f = Significand();
+ int e = Exponent();
+
+ // The current double could be a denormal.
+ while ((f & kHiddenBit) == 0) {
+ f <<= 1;
+ e--;
+ }
+ // Do the final shifts in one go.
+ f <<= DiyFp::kSignificandSize - kSignificandSize;
+ e -= DiyFp::kSignificandSize - kSignificandSize;
+ return DiyFp(f, e);
+ }
+
+ // Returns the double's bit as uint64.
+ uint64_t AsUint64() const {
+ return d64_;
+ }
+
+ // Returns the next greater double. Returns +infinity on input +infinity.
+ double NextDouble() const {
+ if (d64_ == kInfinity) return Double(kInfinity).value();
+ if (Sign() < 0 && Significand() == 0) {
+ // -0.0
+ return 0.0;
+ }
+ if (Sign() < 0) {
+ return Double(d64_ - 1).value();
+ } else {
+ return Double(d64_ + 1).value();
+ }
+ }
+
+ double PreviousDouble() const {
+ if (d64_ == (kInfinity | kSignMask)) return -Infinity();
+ if (Sign() < 0) {
+ return Double(d64_ + 1).value();
+ } else {
+ if (Significand() == 0) return -0.0;
+ return Double(d64_ - 1).value();
+ }
+ }
+
+ int Exponent() const {
+ if (IsDenormal()) return kDenormalExponent;
+
+ uint64_t d64 = AsUint64();
+ int biased_e =
+ static_cast<int>((d64 & kExponentMask) >> kPhysicalSignificandSize);
+ return biased_e - kExponentBias;
+ }
+
+ uint64_t Significand() const {
+ uint64_t d64 = AsUint64();
+ uint64_t significand = d64 & kSignificandMask;
+ if (!IsDenormal()) {
+ return significand + kHiddenBit;
+ } else {
+ return significand;
+ }
+ }
+
+ // Returns true if the double is a denormal.
+ bool IsDenormal() const {
+ uint64_t d64 = AsUint64();
+ return (d64 & kExponentMask) == 0;
+ }
+
+ // We consider denormals not to be special.
+ // Hence only Infinity and NaN are special.
+ bool IsSpecial() const {
+ uint64_t d64 = AsUint64();
+ return (d64 & kExponentMask) == kExponentMask;
+ }
+
+ bool IsNan() const {
+ uint64_t d64 = AsUint64();
+ return ((d64 & kExponentMask) == kExponentMask) &&
+ ((d64 & kSignificandMask) != 0);
+ }
+
+ bool IsQuietNan() const {
+ return IsNan() && ((AsUint64() & kQuietNanBit) != 0);
+ }
+
+ bool IsSignalingNan() const {
+ return IsNan() && ((AsUint64() & kQuietNanBit) == 0);
+ }
+
+
+ bool IsInfinite() const {
+ uint64_t d64 = AsUint64();
+ return ((d64 & kExponentMask) == kExponentMask) &&
+ ((d64 & kSignificandMask) == 0);
+ }
+
+ int Sign() const {
+ uint64_t d64 = AsUint64();
+ return (d64 & kSignMask) == 0? 1: -1;
+ }
+
+ // Precondition: the value encoded by this Double must be greater or equal
+ // than +0.0.
+ DiyFp UpperBoundary() const {
+ DOUBLE_CONVERSION_ASSERT(Sign() > 0);
+ return DiyFp(Significand() * 2 + 1, Exponent() - 1);
+ }
+
+ // Computes the two boundaries of this.
+ // The bigger boundary (m_plus) is normalized. The lower boundary has the same
+ // exponent as m_plus.
+ // Precondition: the value encoded by this Double must be greater than 0.
+ void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const {
+ DOUBLE_CONVERSION_ASSERT(value() > 0.0);
+ DiyFp v = this->AsDiyFp();
+ DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1));
+ DiyFp m_minus;
+ if (LowerBoundaryIsCloser()) {
+ m_minus = DiyFp((v.f() << 2) - 1, v.e() - 2);
+ } else {
+ m_minus = DiyFp((v.f() << 1) - 1, v.e() - 1);
+ }
+ m_minus.set_f(m_minus.f() << (m_minus.e() - m_plus.e()));
+ m_minus.set_e(m_plus.e());
+ *out_m_plus = m_plus;
+ *out_m_minus = m_minus;
+ }
+
+ bool LowerBoundaryIsCloser() const {
+ // The boundary is closer if the significand is of the form f == 2^p-1 then
+ // the lower boundary is closer.
+ // Think of v = 1000e10 and v- = 9999e9.
+ // Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but
+ // at a distance of 1e8.
+ // The only exception is for the smallest normal: the largest denormal is
+ // at the same distance as its successor.
+ // Note: denormals have the same exponent as the smallest normals.
+ bool physical_significand_is_zero = ((AsUint64() & kSignificandMask) == 0);
+ return physical_significand_is_zero && (Exponent() != kDenormalExponent);
+ }
+
+ double value() const { return uint64_to_double(d64_); }
+
+ // Returns the significand size for a given order of magnitude.
+ // If v = f*2^e with 2^p-1 <= f <= 2^p then p+e is v's order of magnitude.
+ // This function returns the number of significant binary digits v will have
+ // once it's encoded into a double. In almost all cases this is equal to
+ // kSignificandSize. The only exceptions are denormals. They start with
+ // leading zeroes and their effective significand-size is hence smaller.
+ static int SignificandSizeForOrderOfMagnitude(int order) {
+ if (order >= (kDenormalExponent + kSignificandSize)) {
+ return kSignificandSize;
+ }
+ if (order <= kDenormalExponent) return 0;
+ return order - kDenormalExponent;
+ }
+
+ static double Infinity() {
+ return Double(kInfinity).value();
+ }
+
+ static double NaN() {
+ return Double(kNaN).value();
+ }
+
+ private:
+ static const int kDenormalExponent = -kExponentBias + 1;
+ static const uint64_t kInfinity = DOUBLE_CONVERSION_UINT64_2PART_C(0x7FF00000, 00000000);
+ static const uint64_t kNaN = DOUBLE_CONVERSION_UINT64_2PART_C(0x7FF80000, 00000000);
+
+ const uint64_t d64_;
+
+ static uint64_t DiyFpToUint64(DiyFp diy_fp) {
+ uint64_t significand = diy_fp.f();
+ int exponent = diy_fp.e();
+ while (significand > kHiddenBit + kSignificandMask) {
+ significand >>= 1;
+ exponent++;
+ }
+ if (exponent >= kMaxExponent) {
+ return kInfinity;
+ }
+ if (exponent < kDenormalExponent) {
+ return 0;
+ }
+ while (exponent > kDenormalExponent && (significand & kHiddenBit) == 0) {
+ significand <<= 1;
+ exponent--;
+ }
+ uint64_t biased_exponent;
+ if (exponent == kDenormalExponent && (significand & kHiddenBit) == 0) {
+ biased_exponent = 0;
+ } else {
+ biased_exponent = static_cast<uint64_t>(exponent + kExponentBias);
+ }
+ return (significand & kSignificandMask) |
+ (biased_exponent << kPhysicalSignificandSize);
+ }
+
+ DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN(Double);
+};
+
+class Single {
+ public:
+ static const uint32_t kSignMask = 0x80000000;
+ static const uint32_t kExponentMask = 0x7F800000;
+ static const uint32_t kSignificandMask = 0x007FFFFF;
+ static const uint32_t kHiddenBit = 0x00800000;
+ static const uint32_t kQuietNanBit = 0x00400000;
+ static const int kPhysicalSignificandSize = 23; // Excludes the hidden bit.
+ static const int kSignificandSize = 24;
+
+ Single() : d32_(0) {}
+ explicit Single(float f) : d32_(float_to_uint32(f)) {}
+ explicit Single(uint32_t d32) : d32_(d32) {}
+
+ // The value encoded by this Single must be greater or equal to +0.0.
+ // It must not be special (infinity, or NaN).
+ DiyFp AsDiyFp() const {
+ DOUBLE_CONVERSION_ASSERT(Sign() > 0);
+ DOUBLE_CONVERSION_ASSERT(!IsSpecial());
+ return DiyFp(Significand(), Exponent());
+ }
+
+ // Returns the single's bit as uint64.
+ uint32_t AsUint32() const {
+ return d32_;
+ }
+
+ int Exponent() const {
+ if (IsDenormal()) return kDenormalExponent;
+
+ uint32_t d32 = AsUint32();
+ int biased_e =
+ static_cast<int>((d32 & kExponentMask) >> kPhysicalSignificandSize);
+ return biased_e - kExponentBias;
+ }
+
+ uint32_t Significand() const {
+ uint32_t d32 = AsUint32();
+ uint32_t significand = d32 & kSignificandMask;
+ if (!IsDenormal()) {
+ return significand + kHiddenBit;
+ } else {
+ return significand;
+ }
+ }
+
+ // Returns true if the single is a denormal.
+ bool IsDenormal() const {
+ uint32_t d32 = AsUint32();
+ return (d32 & kExponentMask) == 0;
+ }
+
+ // We consider denormals not to be special.
+ // Hence only Infinity and NaN are special.
+ bool IsSpecial() const {
+ uint32_t d32 = AsUint32();
+ return (d32 & kExponentMask) == kExponentMask;
+ }
+
+ bool IsNan() const {
+ uint32_t d32 = AsUint32();
+ return ((d32 & kExponentMask) == kExponentMask) &&
+ ((d32 & kSignificandMask) != 0);
+ }
+
+ bool IsQuietNan() const {
+ return IsNan() && ((AsUint32() & kQuietNanBit) != 0);
+ }
+
+ bool IsSignalingNan() const {
+ return IsNan() && ((AsUint32() & kQuietNanBit) == 0);
+ }
+
+
+ bool IsInfinite() const {
+ uint32_t d32 = AsUint32();
+ return ((d32 & kExponentMask) == kExponentMask) &&
+ ((d32 & kSignificandMask) == 0);
+ }
+
+ int Sign() const {
+ uint32_t d32 = AsUint32();
+ return (d32 & kSignMask) == 0? 1: -1;
+ }
+
+ // Computes the two boundaries of this.
+ // The bigger boundary (m_plus) is normalized. The lower boundary has the same
+ // exponent as m_plus.
+ // Precondition: the value encoded by this Single must be greater than 0.
+ void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const {
+ DOUBLE_CONVERSION_ASSERT(value() > 0.0);
+ DiyFp v = this->AsDiyFp();
+ DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1));
+ DiyFp m_minus;
+ if (LowerBoundaryIsCloser()) {
+ m_minus = DiyFp((v.f() << 2) - 1, v.e() - 2);
+ } else {
+ m_minus = DiyFp((v.f() << 1) - 1, v.e() - 1);
+ }
+ m_minus.set_f(m_minus.f() << (m_minus.e() - m_plus.e()));
+ m_minus.set_e(m_plus.e());
+ *out_m_plus = m_plus;
+ *out_m_minus = m_minus;
+ }
+
+ // Precondition: the value encoded by this Single must be greater or equal
+ // than +0.0.
+ DiyFp UpperBoundary() const {
+ DOUBLE_CONVERSION_ASSERT(Sign() > 0);
+ return DiyFp(Significand() * 2 + 1, Exponent() - 1);
+ }
+
+ bool LowerBoundaryIsCloser() const {
+ // The boundary is closer if the significand is of the form f == 2^p-1 then
+ // the lower boundary is closer.
+ // Think of v = 1000e10 and v- = 9999e9.
+ // Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but
+ // at a distance of 1e8.
+ // The only exception is for the smallest normal: the largest denormal is
+ // at the same distance as its successor.
+ // Note: denormals have the same exponent as the smallest normals.
+ bool physical_significand_is_zero = ((AsUint32() & kSignificandMask) == 0);
+ return physical_significand_is_zero && (Exponent() != kDenormalExponent);
+ }
+
+ float value() const { return uint32_to_float(d32_); }
+
+ static float Infinity() {
+ return Single(kInfinity).value();
+ }
+
+ static float NaN() {
+ return Single(kNaN).value();
+ }
+
+ private:
+ static const int kExponentBias = 0x7F + kPhysicalSignificandSize;
+ static const int kDenormalExponent = -kExponentBias + 1;
+ static const int kMaxExponent = 0xFF - kExponentBias;
+ static const uint32_t kInfinity = 0x7F800000;
+ static const uint32_t kNaN = 0x7FC00000;
+
+ const uint32_t d32_;
+
+ DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN(Single);
+};
+
+} // namespace double_conversion
+
+// ICU PATCH: Close ICU namespace
+U_NAMESPACE_END
+
+#endif // DOUBLE_CONVERSION_DOUBLE_H_
+#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
diff --git a/contrib/libs/icu/i18n/double-conversion-string-to-double.cpp b/contrib/libs/icu/i18n/double-conversion-string-to-double.cpp
index 548cad1f30..232b61f4f8 100644
--- a/contrib/libs/icu/i18n/double-conversion-string-to-double.cpp
+++ b/contrib/libs/icu/i18n/double-conversion-string-to-double.cpp
@@ -1,789 +1,789 @@
-// © 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
-
-// ICU PATCH: Do not include std::locale.
-
-#include <climits>
-// #include <locale>
-#include <cmath>
-
-// ICU PATCH: Customize header file paths for ICU.
-
-#include "double-conversion-string-to-double.h"
-
-#include "double-conversion-ieee.h"
-#include "double-conversion-strtod.h"
-#include "double-conversion-utils.h"
-
-// ICU PATCH: Wrap in ICU namespace
-U_NAMESPACE_BEGIN
-
-namespace double_conversion {
-
-namespace {
-
-inline char ToLower(char ch) {
-#if 0 // do not include std::locale in ICU
- static const std::ctype<char>& cType =
- std::use_facet<std::ctype<char> >(std::locale::classic());
- return cType.tolower(ch);
-#else
- (void)ch;
- DOUBLE_CONVERSION_UNREACHABLE();
-#endif
-}
-
-inline char Pass(char ch) {
- return ch;
-}
-
-template <class Iterator, class Converter>
-static inline bool ConsumeSubStringImpl(Iterator* current,
- Iterator end,
- const char* substring,
- Converter converter) {
- DOUBLE_CONVERSION_ASSERT(converter(**current) == *substring);
- for (substring++; *substring != '\0'; substring++) {
- ++*current;
- if (*current == end || converter(**current) != *substring) {
- return false;
- }
- }
- ++*current;
- return true;
-}
-
-// Consumes the given substring from the iterator.
-// Returns false, if the substring does not match.
-template <class Iterator>
-static bool ConsumeSubString(Iterator* current,
- Iterator end,
- const char* substring,
- bool allow_case_insensitivity) {
- if (allow_case_insensitivity) {
- return ConsumeSubStringImpl(current, end, substring, ToLower);
- } else {
- return ConsumeSubStringImpl(current, end, substring, Pass);
- }
-}
-
-// Consumes first character of the str is equal to ch
-inline bool ConsumeFirstCharacter(char ch,
- const char* str,
- bool case_insensitivity) {
- return case_insensitivity ? ToLower(ch) == str[0] : ch == str[0];
-}
-} // namespace
-
-// Maximum number of significant digits in decimal representation.
-// The longest possible double in decimal representation is
-// (2^53 - 1) * 2 ^ -1074 that is (2 ^ 53 - 1) * 5 ^ 1074 / 10 ^ 1074
-// (768 digits). If we parse a number whose first digits are equal to a
-// mean of 2 adjacent doubles (that could have up to 769 digits) the result
-// must be rounded to the bigger one unless the tail consists of zeros, so
-// we don't need to preserve all the digits.
-const int kMaxSignificantDigits = 772;
-
-
-static const char kWhitespaceTable7[] = { 32, 13, 10, 9, 11, 12 };
-static const int kWhitespaceTable7Length = DOUBLE_CONVERSION_ARRAY_SIZE(kWhitespaceTable7);
-
-
-static const uc16 kWhitespaceTable16[] = {
- 160, 8232, 8233, 5760, 6158, 8192, 8193, 8194, 8195,
- 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8239, 8287, 12288, 65279
-};
-static const int kWhitespaceTable16Length = DOUBLE_CONVERSION_ARRAY_SIZE(kWhitespaceTable16);
-
-
-static bool isWhitespace(int x) {
- if (x < 128) {
- for (int i = 0; i < kWhitespaceTable7Length; i++) {
- if (kWhitespaceTable7[i] == x) return true;
- }
- } else {
- for (int i = 0; i < kWhitespaceTable16Length; i++) {
- if (kWhitespaceTable16[i] == x) return true;
- }
- }
- return false;
-}
-
-
-// Returns true if a nonspace found and false if the end has reached.
-template <class Iterator>
-static inline bool AdvanceToNonspace(Iterator* current, Iterator end) {
- while (*current != end) {
- if (!isWhitespace(**current)) return true;
- ++*current;
- }
- return false;
-}
-
-
-static bool isDigit(int x, int radix) {
- return (x >= '0' && x <= '9' && x < '0' + radix)
- || (radix > 10 && x >= 'a' && x < 'a' + radix - 10)
- || (radix > 10 && x >= 'A' && x < 'A' + radix - 10);
-}
-
-
-static double SignedZero(bool sign) {
- return sign ? -0.0 : 0.0;
-}
-
-
-// Returns true if 'c' is a decimal digit that is valid for the given radix.
-//
-// The function is small and could be inlined, but VS2012 emitted a warning
-// because it constant-propagated the radix and concluded that the last
-// condition was always true. By moving it into a separate function the
-// compiler wouldn't warn anymore.
-#ifdef _MSC_VER
-#pragma optimize("",off)
-static bool IsDecimalDigitForRadix(int c, int radix) {
- return '0' <= c && c <= '9' && (c - '0') < radix;
-}
-#pragma optimize("",on)
-#else
-static bool inline IsDecimalDigitForRadix(int c, int radix) {
- return '0' <= c && c <= '9' && (c - '0') < radix;
-}
-#endif
-// Returns true if 'c' is a character digit that is valid for the given radix.
-// The 'a_character' should be 'a' or 'A'.
-//
-// The function is small and could be inlined, but VS2012 emitted a warning
-// because it constant-propagated the radix and concluded that the first
-// condition was always false. By moving it into a separate function the
-// compiler wouldn't warn anymore.
-static bool IsCharacterDigitForRadix(int c, int radix, char a_character) {
- return radix > 10 && c >= a_character && c < a_character + radix - 10;
-}
-
-// Returns true, when the iterator is equal to end.
-template<class Iterator>
-static bool Advance (Iterator* it, uc16 separator, int base, Iterator& end) {
- if (separator == StringToDoubleConverter::kNoSeparator) {
- ++(*it);
- return *it == end;
- }
- if (!isDigit(**it, base)) {
- ++(*it);
- return *it == end;
- }
- ++(*it);
- if (*it == end) return true;
- if (*it + 1 == end) return false;
- if (**it == separator && isDigit(*(*it + 1), base)) {
- ++(*it);
- }
- return *it == end;
-}
-
-// Checks whether the string in the range start-end is a hex-float string.
-// This function assumes that the leading '0x'/'0X' is already consumed.
-//
-// Hex float strings are of one of the following forms:
-// - hex_digits+ 'p' ('+'|'-')? exponent_digits+
-// - hex_digits* '.' hex_digits+ 'p' ('+'|'-')? exponent_digits+
-// - hex_digits+ '.' 'p' ('+'|'-')? exponent_digits+
-template<class Iterator>
-static bool IsHexFloatString(Iterator start,
- Iterator end,
- uc16 separator,
- bool allow_trailing_junk) {
- DOUBLE_CONVERSION_ASSERT(start != end);
-
- Iterator current = start;
-
- bool saw_digit = false;
- while (isDigit(*current, 16)) {
- saw_digit = true;
- if (Advance(&current, separator, 16, end)) return false;
- }
- if (*current == '.') {
- if (Advance(&current, separator, 16, end)) return false;
- while (isDigit(*current, 16)) {
- saw_digit = true;
- if (Advance(&current, separator, 16, end)) return false;
- }
- }
- if (!saw_digit) return false;
- if (*current != 'p' && *current != 'P') return false;
- if (Advance(&current, separator, 16, end)) return false;
- if (*current == '+' || *current == '-') {
- if (Advance(&current, separator, 16, end)) return false;
- }
- if (!isDigit(*current, 10)) return false;
- if (Advance(&current, separator, 16, end)) return true;
- while (isDigit(*current, 10)) {
- if (Advance(&current, separator, 16, end)) return true;
- }
- return allow_trailing_junk || !AdvanceToNonspace(&current, end);
-}
-
-
-// Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end.
-//
-// If parse_as_hex_float is true, then the string must be a valid
-// hex-float.
-template <int radix_log_2, class Iterator>
-static double RadixStringToIeee(Iterator* current,
- Iterator end,
- bool sign,
- uc16 separator,
- bool parse_as_hex_float,
- bool allow_trailing_junk,
- double junk_string_value,
- bool read_as_double,
- bool* result_is_junk) {
- DOUBLE_CONVERSION_ASSERT(*current != end);
- DOUBLE_CONVERSION_ASSERT(!parse_as_hex_float ||
- IsHexFloatString(*current, end, separator, allow_trailing_junk));
-
- const int kDoubleSize = Double::kSignificandSize;
- const int kSingleSize = Single::kSignificandSize;
- const int kSignificandSize = read_as_double? kDoubleSize: kSingleSize;
-
- *result_is_junk = true;
-
- int64_t number = 0;
- int exponent = 0;
- const int radix = (1 << radix_log_2);
- // Whether we have encountered a '.' and are parsing the decimal digits.
- // Only relevant if parse_as_hex_float is true.
- bool post_decimal = false;
-
- // Skip leading 0s.
- while (**current == '0') {
- if (Advance(current, separator, radix, end)) {
- *result_is_junk = false;
- return SignedZero(sign);
- }
- }
-
- while (true) {
- int digit;
- if (IsDecimalDigitForRadix(**current, radix)) {
- digit = static_cast<char>(**current) - '0';
- if (post_decimal) exponent -= radix_log_2;
- } else if (IsCharacterDigitForRadix(**current, radix, 'a')) {
- digit = static_cast<char>(**current) - 'a' + 10;
- if (post_decimal) exponent -= radix_log_2;
- } else if (IsCharacterDigitForRadix(**current, radix, 'A')) {
- digit = static_cast<char>(**current) - 'A' + 10;
- if (post_decimal) exponent -= radix_log_2;
- } else if (parse_as_hex_float && **current == '.') {
- post_decimal = true;
- Advance(current, separator, radix, end);
- DOUBLE_CONVERSION_ASSERT(*current != end);
- continue;
- } else if (parse_as_hex_float && (**current == 'p' || **current == 'P')) {
- break;
- } else {
- if (allow_trailing_junk || !AdvanceToNonspace(current, end)) {
- break;
- } else {
- return junk_string_value;
- }
- }
-
- number = number * radix + digit;
- int overflow = static_cast<int>(number >> kSignificandSize);
- if (overflow != 0) {
- // Overflow occurred. Need to determine which direction to round the
- // result.
- int overflow_bits_count = 1;
- while (overflow > 1) {
- overflow_bits_count++;
- overflow >>= 1;
- }
-
- int dropped_bits_mask = ((1 << overflow_bits_count) - 1);
- int dropped_bits = static_cast<int>(number) & dropped_bits_mask;
- number >>= overflow_bits_count;
- exponent += overflow_bits_count;
-
- bool zero_tail = true;
- for (;;) {
- if (Advance(current, separator, radix, end)) break;
- if (parse_as_hex_float && **current == '.') {
- // Just run over the '.'. We are just trying to see whether there is
- // a non-zero digit somewhere.
- Advance(current, separator, radix, end);
- DOUBLE_CONVERSION_ASSERT(*current != end);
- post_decimal = true;
- }
- if (!isDigit(**current, radix)) break;
- zero_tail = zero_tail && **current == '0';
- if (!post_decimal) exponent += radix_log_2;
- }
-
- if (!parse_as_hex_float &&
- !allow_trailing_junk &&
- AdvanceToNonspace(current, end)) {
- return junk_string_value;
- }
-
- int middle_value = (1 << (overflow_bits_count - 1));
- if (dropped_bits > middle_value) {
- number++; // Rounding up.
- } else if (dropped_bits == middle_value) {
- // Rounding to even to consistency with decimals: half-way case rounds
- // up if significant part is odd and down otherwise.
- if ((number & 1) != 0 || !zero_tail) {
- number++; // Rounding up.
- }
- }
-
- // Rounding up may cause overflow.
- if ((number & ((int64_t)1 << kSignificandSize)) != 0) {
- exponent++;
- number >>= 1;
- }
- break;
- }
- if (Advance(current, separator, radix, end)) break;
- }
-
- DOUBLE_CONVERSION_ASSERT(number < ((int64_t)1 << kSignificandSize));
- DOUBLE_CONVERSION_ASSERT(static_cast<int64_t>(static_cast<double>(number)) == number);
-
- *result_is_junk = false;
-
- if (parse_as_hex_float) {
- DOUBLE_CONVERSION_ASSERT(**current == 'p' || **current == 'P');
- Advance(current, separator, radix, end);
- DOUBLE_CONVERSION_ASSERT(*current != end);
- bool is_negative = false;
- if (**current == '+') {
- Advance(current, separator, radix, end);
- DOUBLE_CONVERSION_ASSERT(*current != end);
- } else if (**current == '-') {
- is_negative = true;
- Advance(current, separator, radix, end);
- DOUBLE_CONVERSION_ASSERT(*current != end);
- }
- int written_exponent = 0;
- while (IsDecimalDigitForRadix(**current, 10)) {
- // No need to read exponents if they are too big. That could potentially overflow
- // the `written_exponent` variable.
- if (abs(written_exponent) <= 100 * Double::kMaxExponent) {
- written_exponent = 10 * written_exponent + **current - '0';
- }
- if (Advance(current, separator, radix, end)) break;
- }
- if (is_negative) written_exponent = -written_exponent;
- exponent += written_exponent;
- }
-
- if (exponent == 0 || number == 0) {
- if (sign) {
- if (number == 0) return -0.0;
- number = -number;
- }
- return static_cast<double>(number);
- }
-
- DOUBLE_CONVERSION_ASSERT(number != 0);
- double result = Double(DiyFp(number, exponent)).value();
- return sign ? -result : result;
-}
-
-template <class Iterator>
-double StringToDoubleConverter::StringToIeee(
- Iterator input,
- int length,
- bool read_as_double,
- int* processed_characters_count) const {
- Iterator current = input;
- Iterator end = input + length;
-
- *processed_characters_count = 0;
-
- const bool allow_trailing_junk = (flags_ & ALLOW_TRAILING_JUNK) != 0;
- const bool allow_leading_spaces = (flags_ & ALLOW_LEADING_SPACES) != 0;
- const bool allow_trailing_spaces = (flags_ & ALLOW_TRAILING_SPACES) != 0;
- const bool allow_spaces_after_sign = (flags_ & ALLOW_SPACES_AFTER_SIGN) != 0;
- const bool allow_case_insensitivity = (flags_ & ALLOW_CASE_INSENSITIVITY) != 0;
-
- // To make sure that iterator dereferencing is valid the following
- // convention is used:
- // 1. Each '++current' statement is followed by check for equality to 'end'.
- // 2. If AdvanceToNonspace returned false then current == end.
- // 3. If 'current' becomes equal to 'end' the function returns or goes to
- // 'parsing_done'.
- // 4. 'current' is not dereferenced after the 'parsing_done' label.
- // 5. Code before 'parsing_done' may rely on 'current != end'.
- if (current == end) return empty_string_value_;
-
- if (allow_leading_spaces || allow_trailing_spaces) {
- if (!AdvanceToNonspace(&current, end)) {
- *processed_characters_count = static_cast<int>(current - input);
- return empty_string_value_;
- }
- if (!allow_leading_spaces && (input != current)) {
- // No leading spaces allowed, but AdvanceToNonspace moved forward.
- return junk_string_value_;
- }
- }
-
- // Exponent will be adjusted if insignificant digits of the integer part
- // or insignificant leading zeros of the fractional part are dropped.
- int exponent = 0;
- int significant_digits = 0;
- int insignificant_digits = 0;
- bool nonzero_digit_dropped = false;
-
- bool sign = false;
-
- if (*current == '+' || *current == '-') {
- sign = (*current == '-');
- ++current;
- Iterator next_non_space = current;
- // Skip following spaces (if allowed).
- if (!AdvanceToNonspace(&next_non_space, end)) return junk_string_value_;
- if (!allow_spaces_after_sign && (current != next_non_space)) {
- return junk_string_value_;
- }
- current = next_non_space;
- }
-
- if (infinity_symbol_ != NULL) {
- if (ConsumeFirstCharacter(*current, infinity_symbol_, allow_case_insensitivity)) {
- if (!ConsumeSubString(&current, end, infinity_symbol_, allow_case_insensitivity)) {
- return junk_string_value_;
- }
-
- if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) {
- return junk_string_value_;
- }
- if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
- return junk_string_value_;
- }
-
- *processed_characters_count = static_cast<int>(current - input);
- return sign ? -Double::Infinity() : Double::Infinity();
- }
- }
-
- if (nan_symbol_ != NULL) {
- if (ConsumeFirstCharacter(*current, nan_symbol_, allow_case_insensitivity)) {
- if (!ConsumeSubString(&current, end, nan_symbol_, allow_case_insensitivity)) {
- return junk_string_value_;
- }
-
- if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) {
- return junk_string_value_;
- }
- if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
- return junk_string_value_;
- }
-
- *processed_characters_count = static_cast<int>(current - input);
- return sign ? -Double::NaN() : Double::NaN();
- }
- }
-
- bool leading_zero = false;
- if (*current == '0') {
- if (Advance(&current, separator_, 10, end)) {
- *processed_characters_count = static_cast<int>(current - input);
- return SignedZero(sign);
- }
-
- leading_zero = true;
-
- // It could be hexadecimal value.
- if (((flags_ & ALLOW_HEX) || (flags_ & ALLOW_HEX_FLOATS)) &&
- (*current == 'x' || *current == 'X')) {
- ++current;
-
- if (current == end) return junk_string_value_; // "0x"
-
- bool parse_as_hex_float = (flags_ & ALLOW_HEX_FLOATS) &&
- IsHexFloatString(current, end, separator_, allow_trailing_junk);
-
- if (!parse_as_hex_float && !isDigit(*current, 16)) {
- return junk_string_value_;
- }
-
- bool result_is_junk;
- double result = RadixStringToIeee<4>(&current,
- end,
- sign,
- separator_,
- parse_as_hex_float,
- allow_trailing_junk,
- junk_string_value_,
- read_as_double,
- &result_is_junk);
- if (!result_is_junk) {
- if (allow_trailing_spaces) AdvanceToNonspace(&current, end);
- *processed_characters_count = static_cast<int>(current - input);
- }
- return result;
- }
-
- // Ignore leading zeros in the integer part.
- while (*current == '0') {
- if (Advance(&current, separator_, 10, end)) {
- *processed_characters_count = static_cast<int>(current - input);
- return SignedZero(sign);
- }
- }
- }
-
- bool octal = leading_zero && (flags_ & ALLOW_OCTALS) != 0;
-
- // The longest form of simplified number is: "-<significant digits>.1eXXX\0".
- const int kBufferSize = kMaxSignificantDigits + 10;
- DOUBLE_CONVERSION_STACK_UNINITIALIZED char
- buffer[kBufferSize]; // NOLINT: size is known at compile time.
- int buffer_pos = 0;
-
- // Copy significant digits of the integer part (if any) to the buffer.
- while (*current >= '0' && *current <= '9') {
- if (significant_digits < kMaxSignificantDigits) {
- DOUBLE_CONVERSION_ASSERT(buffer_pos < kBufferSize);
- buffer[buffer_pos++] = static_cast<char>(*current);
- significant_digits++;
- // Will later check if it's an octal in the buffer.
- } else {
- insignificant_digits++; // Move the digit into the exponential part.
- nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
- }
- octal = octal && *current < '8';
- if (Advance(&current, separator_, 10, end)) goto parsing_done;
- }
-
- if (significant_digits == 0) {
- octal = false;
- }
-
- if (*current == '.') {
- if (octal && !allow_trailing_junk) return junk_string_value_;
- if (octal) goto parsing_done;
-
- if (Advance(&current, separator_, 10, end)) {
- if (significant_digits == 0 && !leading_zero) {
- return junk_string_value_;
- } else {
- goto parsing_done;
- }
- }
-
- if (significant_digits == 0) {
- // octal = false;
- // Integer part consists of 0 or is absent. Significant digits start after
- // leading zeros (if any).
- while (*current == '0') {
- if (Advance(&current, separator_, 10, end)) {
- *processed_characters_count = static_cast<int>(current - input);
- return SignedZero(sign);
- }
- exponent--; // Move this 0 into the exponent.
- }
- }
-
- // There is a fractional part.
- // We don't emit a '.', but adjust the exponent instead.
- while (*current >= '0' && *current <= '9') {
- if (significant_digits < kMaxSignificantDigits) {
- DOUBLE_CONVERSION_ASSERT(buffer_pos < kBufferSize);
- buffer[buffer_pos++] = static_cast<char>(*current);
- significant_digits++;
- exponent--;
- } else {
- // Ignore insignificant digits in the fractional part.
- nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
- }
- if (Advance(&current, separator_, 10, end)) goto parsing_done;
- }
- }
-
- if (!leading_zero && exponent == 0 && significant_digits == 0) {
- // If leading_zeros is true then the string contains zeros.
- // If exponent < 0 then string was [+-]\.0*...
- // If significant_digits != 0 the string is not equal to 0.
- // Otherwise there are no digits in the string.
- return junk_string_value_;
- }
-
- // Parse exponential part.
- if (*current == 'e' || *current == 'E') {
- if (octal && !allow_trailing_junk) return junk_string_value_;
- if (octal) goto parsing_done;
- Iterator junk_begin = current;
- ++current;
- if (current == end) {
- if (allow_trailing_junk) {
- current = junk_begin;
- goto parsing_done;
- } else {
- return junk_string_value_;
- }
- }
- char exponen_sign = '+';
- if (*current == '+' || *current == '-') {
- exponen_sign = static_cast<char>(*current);
- ++current;
- if (current == end) {
- if (allow_trailing_junk) {
- current = junk_begin;
- goto parsing_done;
- } else {
- return junk_string_value_;
- }
- }
- }
-
- if (current == end || *current < '0' || *current > '9') {
- if (allow_trailing_junk) {
- current = junk_begin;
- goto parsing_done;
- } else {
- return junk_string_value_;
- }
- }
-
- const int max_exponent = INT_MAX / 2;
- DOUBLE_CONVERSION_ASSERT(-max_exponent / 2 <= exponent && exponent <= max_exponent / 2);
- int num = 0;
- do {
- // Check overflow.
- int digit = *current - '0';
- if (num >= max_exponent / 10
- && !(num == max_exponent / 10 && digit <= max_exponent % 10)) {
- num = max_exponent;
- } else {
- num = num * 10 + digit;
- }
- ++current;
- } while (current != end && *current >= '0' && *current <= '9');
-
- exponent += (exponen_sign == '-' ? -num : num);
- }
-
- if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) {
- return junk_string_value_;
- }
- if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
- return junk_string_value_;
- }
- if (allow_trailing_spaces) {
- AdvanceToNonspace(&current, end);
- }
-
- parsing_done:
- exponent += insignificant_digits;
-
- if (octal) {
- double result;
- bool result_is_junk;
- char* start = buffer;
- result = RadixStringToIeee<3>(&start,
- buffer + buffer_pos,
- sign,
- separator_,
- false, // Don't parse as hex_float.
- allow_trailing_junk,
- junk_string_value_,
- read_as_double,
- &result_is_junk);
- DOUBLE_CONVERSION_ASSERT(!result_is_junk);
- *processed_characters_count = static_cast<int>(current - input);
- return result;
- }
-
- if (nonzero_digit_dropped) {
- buffer[buffer_pos++] = '1';
- exponent--;
- }
-
- DOUBLE_CONVERSION_ASSERT(buffer_pos < kBufferSize);
- buffer[buffer_pos] = '\0';
-
- double converted;
- if (read_as_double) {
- converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent);
- } else {
- converted = Strtof(Vector<const char>(buffer, buffer_pos), exponent);
- }
- *processed_characters_count = static_cast<int>(current - input);
- return sign? -converted: converted;
-}
-
-
-double StringToDoubleConverter::StringToDouble(
- const char* buffer,
- int length,
- int* processed_characters_count) const {
- return StringToIeee(buffer, length, true, processed_characters_count);
-}
-
-
-double StringToDoubleConverter::StringToDouble(
- const uc16* buffer,
- int length,
- int* processed_characters_count) const {
- return StringToIeee(buffer, length, true, processed_characters_count);
-}
-
-
-float StringToDoubleConverter::StringToFloat(
- const char* buffer,
- int length,
- int* processed_characters_count) const {
- return static_cast<float>(StringToIeee(buffer, length, false,
- processed_characters_count));
-}
-
-
-float StringToDoubleConverter::StringToFloat(
- const uc16* buffer,
- int length,
- int* processed_characters_count) const {
- return static_cast<float>(StringToIeee(buffer, length, false,
- processed_characters_count));
-}
-
-} // namespace double_conversion
-
-// ICU PATCH: Close ICU namespace
-U_NAMESPACE_END
-#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
+// © 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
+
+// ICU PATCH: Do not include std::locale.
+
+#include <climits>
+// #include <locale>
+#include <cmath>
+
+// ICU PATCH: Customize header file paths for ICU.
+
+#include "double-conversion-string-to-double.h"
+
+#include "double-conversion-ieee.h"
+#include "double-conversion-strtod.h"
+#include "double-conversion-utils.h"
+
+// ICU PATCH: Wrap in ICU namespace
+U_NAMESPACE_BEGIN
+
+namespace double_conversion {
+
+namespace {
+
+inline char ToLower(char ch) {
+#if 0 // do not include std::locale in ICU
+ static const std::ctype<char>& cType =
+ std::use_facet<std::ctype<char> >(std::locale::classic());
+ return cType.tolower(ch);
+#else
+ (void)ch;
+ DOUBLE_CONVERSION_UNREACHABLE();
+#endif
+}
+
+inline char Pass(char ch) {
+ return ch;
+}
+
+template <class Iterator, class Converter>
+static inline bool ConsumeSubStringImpl(Iterator* current,
+ Iterator end,
+ const char* substring,
+ Converter converter) {
+ DOUBLE_CONVERSION_ASSERT(converter(**current) == *substring);
+ for (substring++; *substring != '\0'; substring++) {
+ ++*current;
+ if (*current == end || converter(**current) != *substring) {
+ return false;
+ }
+ }
+ ++*current;
+ return true;
+}
+
+// Consumes the given substring from the iterator.
+// Returns false, if the substring does not match.
+template <class Iterator>
+static bool ConsumeSubString(Iterator* current,
+ Iterator end,
+ const char* substring,
+ bool allow_case_insensitivity) {
+ if (allow_case_insensitivity) {
+ return ConsumeSubStringImpl(current, end, substring, ToLower);
+ } else {
+ return ConsumeSubStringImpl(current, end, substring, Pass);
+ }
+}
+
+// Consumes first character of the str is equal to ch
+inline bool ConsumeFirstCharacter(char ch,
+ const char* str,
+ bool case_insensitivity) {
+ return case_insensitivity ? ToLower(ch) == str[0] : ch == str[0];
+}
+} // namespace
+
+// Maximum number of significant digits in decimal representation.
+// The longest possible double in decimal representation is
+// (2^53 - 1) * 2 ^ -1074 that is (2 ^ 53 - 1) * 5 ^ 1074 / 10 ^ 1074
+// (768 digits). If we parse a number whose first digits are equal to a
+// mean of 2 adjacent doubles (that could have up to 769 digits) the result
+// must be rounded to the bigger one unless the tail consists of zeros, so
+// we don't need to preserve all the digits.
+const int kMaxSignificantDigits = 772;
+
+
+static const char kWhitespaceTable7[] = { 32, 13, 10, 9, 11, 12 };
+static const int kWhitespaceTable7Length = DOUBLE_CONVERSION_ARRAY_SIZE(kWhitespaceTable7);
+
+
+static const uc16 kWhitespaceTable16[] = {
+ 160, 8232, 8233, 5760, 6158, 8192, 8193, 8194, 8195,
+ 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8239, 8287, 12288, 65279
+};
+static const int kWhitespaceTable16Length = DOUBLE_CONVERSION_ARRAY_SIZE(kWhitespaceTable16);
+
+
+static bool isWhitespace(int x) {
+ if (x < 128) {
+ for (int i = 0; i < kWhitespaceTable7Length; i++) {
+ if (kWhitespaceTable7[i] == x) return true;
+ }
+ } else {
+ for (int i = 0; i < kWhitespaceTable16Length; i++) {
+ if (kWhitespaceTable16[i] == x) return true;
+ }
+ }
+ return false;
+}
+
+
+// Returns true if a nonspace found and false if the end has reached.
+template <class Iterator>
+static inline bool AdvanceToNonspace(Iterator* current, Iterator end) {
+ while (*current != end) {
+ if (!isWhitespace(**current)) return true;
+ ++*current;
+ }
+ return false;
+}
+
+
+static bool isDigit(int x, int radix) {
+ return (x >= '0' && x <= '9' && x < '0' + radix)
+ || (radix > 10 && x >= 'a' && x < 'a' + radix - 10)
+ || (radix > 10 && x >= 'A' && x < 'A' + radix - 10);
+}
+
+
+static double SignedZero(bool sign) {
+ return sign ? -0.0 : 0.0;
+}
+
+
+// Returns true if 'c' is a decimal digit that is valid for the given radix.
+//
+// The function is small and could be inlined, but VS2012 emitted a warning
+// because it constant-propagated the radix and concluded that the last
+// condition was always true. By moving it into a separate function the
+// compiler wouldn't warn anymore.
+#ifdef _MSC_VER
+#pragma optimize("",off)
+static bool IsDecimalDigitForRadix(int c, int radix) {
+ return '0' <= c && c <= '9' && (c - '0') < radix;
+}
+#pragma optimize("",on)
+#else
+static bool inline IsDecimalDigitForRadix(int c, int radix) {
+ return '0' <= c && c <= '9' && (c - '0') < radix;
+}
+#endif
+// Returns true if 'c' is a character digit that is valid for the given radix.
+// The 'a_character' should be 'a' or 'A'.
+//
+// The function is small and could be inlined, but VS2012 emitted a warning
+// because it constant-propagated the radix and concluded that the first
+// condition was always false. By moving it into a separate function the
+// compiler wouldn't warn anymore.
+static bool IsCharacterDigitForRadix(int c, int radix, char a_character) {
+ return radix > 10 && c >= a_character && c < a_character + radix - 10;
+}
+
+// Returns true, when the iterator is equal to end.
+template<class Iterator>
+static bool Advance (Iterator* it, uc16 separator, int base, Iterator& end) {
+ if (separator == StringToDoubleConverter::kNoSeparator) {
+ ++(*it);
+ return *it == end;
+ }
+ if (!isDigit(**it, base)) {
+ ++(*it);
+ return *it == end;
+ }
+ ++(*it);
+ if (*it == end) return true;
+ if (*it + 1 == end) return false;
+ if (**it == separator && isDigit(*(*it + 1), base)) {
+ ++(*it);
+ }
+ return *it == end;
+}
+
+// Checks whether the string in the range start-end is a hex-float string.
+// This function assumes that the leading '0x'/'0X' is already consumed.
+//
+// Hex float strings are of one of the following forms:
+// - hex_digits+ 'p' ('+'|'-')? exponent_digits+
+// - hex_digits* '.' hex_digits+ 'p' ('+'|'-')? exponent_digits+
+// - hex_digits+ '.' 'p' ('+'|'-')? exponent_digits+
+template<class Iterator>
+static bool IsHexFloatString(Iterator start,
+ Iterator end,
+ uc16 separator,
+ bool allow_trailing_junk) {
+ DOUBLE_CONVERSION_ASSERT(start != end);
+
+ Iterator current = start;
+
+ bool saw_digit = false;
+ while (isDigit(*current, 16)) {
+ saw_digit = true;
+ if (Advance(&current, separator, 16, end)) return false;
+ }
+ if (*current == '.') {
+ if (Advance(&current, separator, 16, end)) return false;
+ while (isDigit(*current, 16)) {
+ saw_digit = true;
+ if (Advance(&current, separator, 16, end)) return false;
+ }
+ }
+ if (!saw_digit) return false;
+ if (*current != 'p' && *current != 'P') return false;
+ if (Advance(&current, separator, 16, end)) return false;
+ if (*current == '+' || *current == '-') {
+ if (Advance(&current, separator, 16, end)) return false;
+ }
+ if (!isDigit(*current, 10)) return false;
+ if (Advance(&current, separator, 16, end)) return true;
+ while (isDigit(*current, 10)) {
+ if (Advance(&current, separator, 16, end)) return true;
+ }
+ return allow_trailing_junk || !AdvanceToNonspace(&current, end);
+}
+
+
+// Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end.
+//
+// If parse_as_hex_float is true, then the string must be a valid
+// hex-float.
+template <int radix_log_2, class Iterator>
+static double RadixStringToIeee(Iterator* current,
+ Iterator end,
+ bool sign,
+ uc16 separator,
+ bool parse_as_hex_float,
+ bool allow_trailing_junk,
+ double junk_string_value,
+ bool read_as_double,
+ bool* result_is_junk) {
+ DOUBLE_CONVERSION_ASSERT(*current != end);
+ DOUBLE_CONVERSION_ASSERT(!parse_as_hex_float ||
+ IsHexFloatString(*current, end, separator, allow_trailing_junk));
+
+ const int kDoubleSize = Double::kSignificandSize;
+ const int kSingleSize = Single::kSignificandSize;
+ const int kSignificandSize = read_as_double? kDoubleSize: kSingleSize;
+
+ *result_is_junk = true;
+
+ int64_t number = 0;
+ int exponent = 0;
+ const int radix = (1 << radix_log_2);
+ // Whether we have encountered a '.' and are parsing the decimal digits.
+ // Only relevant if parse_as_hex_float is true.
+ bool post_decimal = false;
+
+ // Skip leading 0s.
+ while (**current == '0') {
+ if (Advance(current, separator, radix, end)) {
+ *result_is_junk = false;
+ return SignedZero(sign);
+ }
+ }
+
+ while (true) {
+ int digit;
+ if (IsDecimalDigitForRadix(**current, radix)) {
+ digit = static_cast<char>(**current) - '0';
+ if (post_decimal) exponent -= radix_log_2;
+ } else if (IsCharacterDigitForRadix(**current, radix, 'a')) {
+ digit = static_cast<char>(**current) - 'a' + 10;
+ if (post_decimal) exponent -= radix_log_2;
+ } else if (IsCharacterDigitForRadix(**current, radix, 'A')) {
+ digit = static_cast<char>(**current) - 'A' + 10;
+ if (post_decimal) exponent -= radix_log_2;
+ } else if (parse_as_hex_float && **current == '.') {
+ post_decimal = true;
+ Advance(current, separator, radix, end);
+ DOUBLE_CONVERSION_ASSERT(*current != end);
+ continue;
+ } else if (parse_as_hex_float && (**current == 'p' || **current == 'P')) {
+ break;
+ } else {
+ if (allow_trailing_junk || !AdvanceToNonspace(current, end)) {
+ break;
+ } else {
+ return junk_string_value;
+ }
+ }
+
+ number = number * radix + digit;
+ int overflow = static_cast<int>(number >> kSignificandSize);
+ if (overflow != 0) {
+ // Overflow occurred. Need to determine which direction to round the
+ // result.
+ int overflow_bits_count = 1;
+ while (overflow > 1) {
+ overflow_bits_count++;
+ overflow >>= 1;
+ }
+
+ int dropped_bits_mask = ((1 << overflow_bits_count) - 1);
+ int dropped_bits = static_cast<int>(number) & dropped_bits_mask;
+ number >>= overflow_bits_count;
+ exponent += overflow_bits_count;
+
+ bool zero_tail = true;
+ for (;;) {
+ if (Advance(current, separator, radix, end)) break;
+ if (parse_as_hex_float && **current == '.') {
+ // Just run over the '.'. We are just trying to see whether there is
+ // a non-zero digit somewhere.
+ Advance(current, separator, radix, end);
+ DOUBLE_CONVERSION_ASSERT(*current != end);
+ post_decimal = true;
+ }
+ if (!isDigit(**current, radix)) break;
+ zero_tail = zero_tail && **current == '0';
+ if (!post_decimal) exponent += radix_log_2;
+ }
+
+ if (!parse_as_hex_float &&
+ !allow_trailing_junk &&
+ AdvanceToNonspace(current, end)) {
+ return junk_string_value;
+ }
+
+ int middle_value = (1 << (overflow_bits_count - 1));
+ if (dropped_bits > middle_value) {
+ number++; // Rounding up.
+ } else if (dropped_bits == middle_value) {
+ // Rounding to even to consistency with decimals: half-way case rounds
+ // up if significant part is odd and down otherwise.
+ if ((number & 1) != 0 || !zero_tail) {
+ number++; // Rounding up.
+ }
+ }
+
+ // Rounding up may cause overflow.
+ if ((number & ((int64_t)1 << kSignificandSize)) != 0) {
+ exponent++;
+ number >>= 1;
+ }
+ break;
+ }
+ if (Advance(current, separator, radix, end)) break;
+ }
+
+ DOUBLE_CONVERSION_ASSERT(number < ((int64_t)1 << kSignificandSize));
+ DOUBLE_CONVERSION_ASSERT(static_cast<int64_t>(static_cast<double>(number)) == number);
+
+ *result_is_junk = false;
+
+ if (parse_as_hex_float) {
+ DOUBLE_CONVERSION_ASSERT(**current == 'p' || **current == 'P');
+ Advance(current, separator, radix, end);
+ DOUBLE_CONVERSION_ASSERT(*current != end);
+ bool is_negative = false;
+ if (**current == '+') {
+ Advance(current, separator, radix, end);
+ DOUBLE_CONVERSION_ASSERT(*current != end);
+ } else if (**current == '-') {
+ is_negative = true;
+ Advance(current, separator, radix, end);
+ DOUBLE_CONVERSION_ASSERT(*current != end);
+ }
+ int written_exponent = 0;
+ while (IsDecimalDigitForRadix(**current, 10)) {
+ // No need to read exponents if they are too big. That could potentially overflow
+ // the `written_exponent` variable.
+ if (abs(written_exponent) <= 100 * Double::kMaxExponent) {
+ written_exponent = 10 * written_exponent + **current - '0';
+ }
+ if (Advance(current, separator, radix, end)) break;
+ }
+ if (is_negative) written_exponent = -written_exponent;
+ exponent += written_exponent;
+ }
+
+ if (exponent == 0 || number == 0) {
+ if (sign) {
+ if (number == 0) return -0.0;
+ number = -number;
+ }
+ return static_cast<double>(number);
+ }
+
+ DOUBLE_CONVERSION_ASSERT(number != 0);
+ double result = Double(DiyFp(number, exponent)).value();
+ return sign ? -result : result;
+}
+
+template <class Iterator>
+double StringToDoubleConverter::StringToIeee(
+ Iterator input,
+ int length,
+ bool read_as_double,
+ int* processed_characters_count) const {
+ Iterator current = input;
+ Iterator end = input + length;
+
+ *processed_characters_count = 0;
+
+ const bool allow_trailing_junk = (flags_ & ALLOW_TRAILING_JUNK) != 0;
+ const bool allow_leading_spaces = (flags_ & ALLOW_LEADING_SPACES) != 0;
+ const bool allow_trailing_spaces = (flags_ & ALLOW_TRAILING_SPACES) != 0;
+ const bool allow_spaces_after_sign = (flags_ & ALLOW_SPACES_AFTER_SIGN) != 0;
+ const bool allow_case_insensitivity = (flags_ & ALLOW_CASE_INSENSITIVITY) != 0;
+
+ // To make sure that iterator dereferencing is valid the following
+ // convention is used:
+ // 1. Each '++current' statement is followed by check for equality to 'end'.
+ // 2. If AdvanceToNonspace returned false then current == end.
+ // 3. If 'current' becomes equal to 'end' the function returns or goes to
+ // 'parsing_done'.
+ // 4. 'current' is not dereferenced after the 'parsing_done' label.
+ // 5. Code before 'parsing_done' may rely on 'current != end'.
+ if (current == end) return empty_string_value_;
+
+ if (allow_leading_spaces || allow_trailing_spaces) {
+ if (!AdvanceToNonspace(&current, end)) {
+ *processed_characters_count = static_cast<int>(current - input);
+ return empty_string_value_;
+ }
+ if (!allow_leading_spaces && (input != current)) {
+ // No leading spaces allowed, but AdvanceToNonspace moved forward.
+ return junk_string_value_;
+ }
+ }
+
+ // Exponent will be adjusted if insignificant digits of the integer part
+ // or insignificant leading zeros of the fractional part are dropped.
+ int exponent = 0;
+ int significant_digits = 0;
+ int insignificant_digits = 0;
+ bool nonzero_digit_dropped = false;
+
+ bool sign = false;
+
+ if (*current == '+' || *current == '-') {
+ sign = (*current == '-');
+ ++current;
+ Iterator next_non_space = current;
+ // Skip following spaces (if allowed).
+ if (!AdvanceToNonspace(&next_non_space, end)) return junk_string_value_;
+ if (!allow_spaces_after_sign && (current != next_non_space)) {
+ return junk_string_value_;
+ }
+ current = next_non_space;
+ }
+
+ if (infinity_symbol_ != NULL) {
+ if (ConsumeFirstCharacter(*current, infinity_symbol_, allow_case_insensitivity)) {
+ if (!ConsumeSubString(&current, end, infinity_symbol_, allow_case_insensitivity)) {
+ return junk_string_value_;
+ }
+
+ if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) {
+ return junk_string_value_;
+ }
+ if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
+ return junk_string_value_;
+ }
+
+ *processed_characters_count = static_cast<int>(current - input);
+ return sign ? -Double::Infinity() : Double::Infinity();
+ }
+ }
+
+ if (nan_symbol_ != NULL) {
+ if (ConsumeFirstCharacter(*current, nan_symbol_, allow_case_insensitivity)) {
+ if (!ConsumeSubString(&current, end, nan_symbol_, allow_case_insensitivity)) {
+ return junk_string_value_;
+ }
+
+ if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) {
+ return junk_string_value_;
+ }
+ if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
+ return junk_string_value_;
+ }
+
+ *processed_characters_count = static_cast<int>(current - input);
+ return sign ? -Double::NaN() : Double::NaN();
+ }
+ }
+
+ bool leading_zero = false;
+ if (*current == '0') {
+ if (Advance(&current, separator_, 10, end)) {
+ *processed_characters_count = static_cast<int>(current - input);
+ return SignedZero(sign);
+ }
+
+ leading_zero = true;
+
+ // It could be hexadecimal value.
+ if (((flags_ & ALLOW_HEX) || (flags_ & ALLOW_HEX_FLOATS)) &&
+ (*current == 'x' || *current == 'X')) {
+ ++current;
+
+ if (current == end) return junk_string_value_; // "0x"
+
+ bool parse_as_hex_float = (flags_ & ALLOW_HEX_FLOATS) &&
+ IsHexFloatString(current, end, separator_, allow_trailing_junk);
+
+ if (!parse_as_hex_float && !isDigit(*current, 16)) {
+ return junk_string_value_;
+ }
+
+ bool result_is_junk;
+ double result = RadixStringToIeee<4>(&current,
+ end,
+ sign,
+ separator_,
+ parse_as_hex_float,
+ allow_trailing_junk,
+ junk_string_value_,
+ read_as_double,
+ &result_is_junk);
+ if (!result_is_junk) {
+ if (allow_trailing_spaces) AdvanceToNonspace(&current, end);
+ *processed_characters_count = static_cast<int>(current - input);
+ }
+ return result;
+ }
+
+ // Ignore leading zeros in the integer part.
+ while (*current == '0') {
+ if (Advance(&current, separator_, 10, end)) {
+ *processed_characters_count = static_cast<int>(current - input);
+ return SignedZero(sign);
+ }
+ }
+ }
+
+ bool octal = leading_zero && (flags_ & ALLOW_OCTALS) != 0;
+
+ // The longest form of simplified number is: "-<significant digits>.1eXXX\0".
+ const int kBufferSize = kMaxSignificantDigits + 10;
+ DOUBLE_CONVERSION_STACK_UNINITIALIZED char
+ buffer[kBufferSize]; // NOLINT: size is known at compile time.
+ int buffer_pos = 0;
+
+ // Copy significant digits of the integer part (if any) to the buffer.
+ while (*current >= '0' && *current <= '9') {
+ if (significant_digits < kMaxSignificantDigits) {
+ DOUBLE_CONVERSION_ASSERT(buffer_pos < kBufferSize);
+ buffer[buffer_pos++] = static_cast<char>(*current);
+ significant_digits++;
+ // Will later check if it's an octal in the buffer.
+ } else {
+ insignificant_digits++; // Move the digit into the exponential part.
+ nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
+ }
+ octal = octal && *current < '8';
+ if (Advance(&current, separator_, 10, end)) goto parsing_done;
+ }
+
+ if (significant_digits == 0) {
+ octal = false;
+ }
+
+ if (*current == '.') {
+ if (octal && !allow_trailing_junk) return junk_string_value_;
+ if (octal) goto parsing_done;
+
+ if (Advance(&current, separator_, 10, end)) {
+ if (significant_digits == 0 && !leading_zero) {
+ return junk_string_value_;
+ } else {
+ goto parsing_done;
+ }
+ }
+
+ if (significant_digits == 0) {
+ // octal = false;
+ // Integer part consists of 0 or is absent. Significant digits start after
+ // leading zeros (if any).
+ while (*current == '0') {
+ if (Advance(&current, separator_, 10, end)) {
+ *processed_characters_count = static_cast<int>(current - input);
+ return SignedZero(sign);
+ }
+ exponent--; // Move this 0 into the exponent.
+ }
+ }
+
+ // There is a fractional part.
+ // We don't emit a '.', but adjust the exponent instead.
+ while (*current >= '0' && *current <= '9') {
+ if (significant_digits < kMaxSignificantDigits) {
+ DOUBLE_CONVERSION_ASSERT(buffer_pos < kBufferSize);
+ buffer[buffer_pos++] = static_cast<char>(*current);
+ significant_digits++;
+ exponent--;
+ } else {
+ // Ignore insignificant digits in the fractional part.
+ nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
+ }
+ if (Advance(&current, separator_, 10, end)) goto parsing_done;
+ }
+ }
+
+ if (!leading_zero && exponent == 0 && significant_digits == 0) {
+ // If leading_zeros is true then the string contains zeros.
+ // If exponent < 0 then string was [+-]\.0*...
+ // If significant_digits != 0 the string is not equal to 0.
+ // Otherwise there are no digits in the string.
+ return junk_string_value_;
+ }
+
+ // Parse exponential part.
+ if (*current == 'e' || *current == 'E') {
+ if (octal && !allow_trailing_junk) return junk_string_value_;
+ if (octal) goto parsing_done;
+ Iterator junk_begin = current;
+ ++current;
+ if (current == end) {
+ if (allow_trailing_junk) {
+ current = junk_begin;
+ goto parsing_done;
+ } else {
+ return junk_string_value_;
+ }
+ }
+ char exponen_sign = '+';
+ if (*current == '+' || *current == '-') {
+ exponen_sign = static_cast<char>(*current);
+ ++current;
+ if (current == end) {
+ if (allow_trailing_junk) {
+ current = junk_begin;
+ goto parsing_done;
+ } else {
+ return junk_string_value_;
+ }
+ }
+ }
+
+ if (current == end || *current < '0' || *current > '9') {
+ if (allow_trailing_junk) {
+ current = junk_begin;
+ goto parsing_done;
+ } else {
+ return junk_string_value_;
+ }
+ }
+
+ const int max_exponent = INT_MAX / 2;
+ DOUBLE_CONVERSION_ASSERT(-max_exponent / 2 <= exponent && exponent <= max_exponent / 2);
+ int num = 0;
+ do {
+ // Check overflow.
+ int digit = *current - '0';
+ if (num >= max_exponent / 10
+ && !(num == max_exponent / 10 && digit <= max_exponent % 10)) {
+ num = max_exponent;
+ } else {
+ num = num * 10 + digit;
+ }
+ ++current;
+ } while (current != end && *current >= '0' && *current <= '9');
+
+ exponent += (exponen_sign == '-' ? -num : num);
+ }
+
+ if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) {
+ return junk_string_value_;
+ }
+ if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
+ return junk_string_value_;
+ }
+ if (allow_trailing_spaces) {
+ AdvanceToNonspace(&current, end);
+ }
+
+ parsing_done:
+ exponent += insignificant_digits;
+
+ if (octal) {
+ double result;
+ bool result_is_junk;
+ char* start = buffer;
+ result = RadixStringToIeee<3>(&start,
+ buffer + buffer_pos,
+ sign,
+ separator_,
+ false, // Don't parse as hex_float.
+ allow_trailing_junk,
+ junk_string_value_,
+ read_as_double,
+ &result_is_junk);
+ DOUBLE_CONVERSION_ASSERT(!result_is_junk);
+ *processed_characters_count = static_cast<int>(current - input);
+ return result;
+ }
+
+ if (nonzero_digit_dropped) {
+ buffer[buffer_pos++] = '1';
+ exponent--;
+ }
+
+ DOUBLE_CONVERSION_ASSERT(buffer_pos < kBufferSize);
+ buffer[buffer_pos] = '\0';
+
+ double converted;
+ if (read_as_double) {
+ converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent);
+ } else {
+ converted = Strtof(Vector<const char>(buffer, buffer_pos), exponent);
+ }
+ *processed_characters_count = static_cast<int>(current - input);
+ return sign? -converted: converted;
+}
+
+
+double StringToDoubleConverter::StringToDouble(
+ const char* buffer,
+ int length,
+ int* processed_characters_count) const {
+ return StringToIeee(buffer, length, true, processed_characters_count);
+}
+
+
+double StringToDoubleConverter::StringToDouble(
+ const uc16* buffer,
+ int length,
+ int* processed_characters_count) const {
+ return StringToIeee(buffer, length, true, processed_characters_count);
+}
+
+
+float StringToDoubleConverter::StringToFloat(
+ const char* buffer,
+ int length,
+ int* processed_characters_count) const {
+ return static_cast<float>(StringToIeee(buffer, length, false,
+ processed_characters_count));
+}
+
+
+float StringToDoubleConverter::StringToFloat(
+ const uc16* buffer,
+ int length,
+ int* processed_characters_count) const {
+ return static_cast<float>(StringToIeee(buffer, length, false,
+ processed_characters_count));
+}
+
+} // namespace double_conversion
+
+// ICU PATCH: Close ICU namespace
+U_NAMESPACE_END
+#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
diff --git a/contrib/libs/icu/i18n/double-conversion-string-to-double.h b/contrib/libs/icu/i18n/double-conversion-string-to-double.h
index 2eb0c1f897..2d1e02e91c 100644
--- a/contrib/libs/icu/i18n/double-conversion-string-to-double.h
+++ b/contrib/libs/icu/i18n/double-conversion-string-to-double.h
@@ -1,244 +1,244 @@
-// © 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 2012 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_STRING_TO_DOUBLE_H_
-#define DOUBLE_CONVERSION_STRING_TO_DOUBLE_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 {
-
-class StringToDoubleConverter {
- public:
- // Enumeration for allowing octals and ignoring junk when converting
- // strings to numbers.
- enum Flags {
- NO_FLAGS = 0,
- ALLOW_HEX = 1,
- ALLOW_OCTALS = 2,
- ALLOW_TRAILING_JUNK = 4,
- ALLOW_LEADING_SPACES = 8,
- ALLOW_TRAILING_SPACES = 16,
- ALLOW_SPACES_AFTER_SIGN = 32,
- ALLOW_CASE_INSENSITIVITY = 64,
- ALLOW_CASE_INSENSIBILITY = 64, // Deprecated
- ALLOW_HEX_FLOATS = 128,
- };
-
- static const uc16 kNoSeparator = '\0';
-
- // Flags should be a bit-or combination of the possible Flags-enum.
- // - NO_FLAGS: no special flags.
- // - ALLOW_HEX: recognizes the prefix "0x". Hex numbers may only be integers.
- // Ex: StringToDouble("0x1234") -> 4660.0
- // In StringToDouble("0x1234.56") the characters ".56" are trailing
- // junk. The result of the call is hence dependent on
- // the ALLOW_TRAILING_JUNK flag and/or the junk value.
- // With this flag "0x" is a junk-string. Even with ALLOW_TRAILING_JUNK,
- // the string will not be parsed as "0" followed by junk.
- //
- // - ALLOW_OCTALS: recognizes the prefix "0" for octals:
- // If a sequence of octal digits starts with '0', then the number is
- // read as octal integer. Octal numbers may only be integers.
- // Ex: StringToDouble("01234") -> 668.0
- // StringToDouble("012349") -> 12349.0 // Not a sequence of octal
- // // digits.
- // In StringToDouble("01234.56") the characters ".56" are trailing
- // junk. The result of the call is hence dependent on
- // the ALLOW_TRAILING_JUNK flag and/or the junk value.
- // In StringToDouble("01234e56") the characters "e56" are trailing
- // junk, too.
- // - ALLOW_TRAILING_JUNK: ignore trailing characters that are not part of
- // a double literal.
- // - ALLOW_LEADING_SPACES: skip over leading whitespace, including spaces,
- // new-lines, and tabs.
- // - ALLOW_TRAILING_SPACES: ignore trailing whitespace.
- // - ALLOW_SPACES_AFTER_SIGN: ignore whitespace after the sign.
- // Ex: StringToDouble("- 123.2") -> -123.2.
- // StringToDouble("+ 123.2") -> 123.2
- // - ALLOW_CASE_INSENSITIVITY: ignore case of characters for special values:
- // infinity and nan.
- // - ALLOW_HEX_FLOATS: allows hexadecimal float literals.
- // This *must* start with "0x" and separate the exponent with "p".
- // Examples: 0x1.2p3 == 9.0
- // 0x10.1p0 == 16.0625
- // ALLOW_HEX and ALLOW_HEX_FLOATS are indendent.
- //
- // empty_string_value is returned when an empty string is given as input.
- // If ALLOW_LEADING_SPACES or ALLOW_TRAILING_SPACES are set, then a string
- // containing only spaces is converted to the 'empty_string_value', too.
- //
- // junk_string_value is returned when
- // a) ALLOW_TRAILING_JUNK is not set, and a junk character (a character not
- // part of a double-literal) is found.
- // b) ALLOW_TRAILING_JUNK is set, but the string does not start with a
- // double literal.
- //
- // infinity_symbol and nan_symbol are strings that are used to detect
- // inputs that represent infinity and NaN. They can be null, in which case
- // they are ignored.
- // The conversion routine first reads any possible signs. Then it compares the
- // following character of the input-string with the first character of
- // the infinity, and nan-symbol. If either matches, the function assumes, that
- // a match has been found, and expects the following input characters to match
- // the remaining characters of the special-value symbol.
- // This means that the following restrictions apply to special-value symbols:
- // - they must not start with signs ('+', or '-'),
- // - they must not have the same first character.
- // - they must not start with digits.
- //
- // If the separator character is not kNoSeparator, then that specific
- // character is ignored when in between two valid digits of the significant.
- // It is not allowed to appear in the exponent.
- // It is not allowed to lead or trail the number.
- // It is not allowed to appear twice next to each other.
- //
- // Examples:
- // flags = ALLOW_HEX | ALLOW_TRAILING_JUNK,
- // empty_string_value = 0.0,
- // junk_string_value = NaN,
- // infinity_symbol = "infinity",
- // nan_symbol = "nan":
- // StringToDouble("0x1234") -> 4660.0.
- // StringToDouble("0x1234K") -> 4660.0.
- // StringToDouble("") -> 0.0 // empty_string_value.
- // StringToDouble(" ") -> NaN // junk_string_value.
- // StringToDouble(" 1") -> NaN // junk_string_value.
- // StringToDouble("0x") -> NaN // junk_string_value.
- // StringToDouble("-123.45") -> -123.45.
- // StringToDouble("--123.45") -> NaN // junk_string_value.
- // StringToDouble("123e45") -> 123e45.
- // StringToDouble("123E45") -> 123e45.
- // StringToDouble("123e+45") -> 123e45.
- // StringToDouble("123E-45") -> 123e-45.
- // StringToDouble("123e") -> 123.0 // trailing junk ignored.
- // StringToDouble("123e-") -> 123.0 // trailing junk ignored.
- // StringToDouble("+NaN") -> NaN // NaN string literal.
- // StringToDouble("-infinity") -> -inf. // infinity literal.
- // StringToDouble("Infinity") -> NaN // junk_string_value.
- //
- // flags = ALLOW_OCTAL | ALLOW_LEADING_SPACES,
- // empty_string_value = 0.0,
- // junk_string_value = NaN,
- // infinity_symbol = NULL,
- // nan_symbol = NULL:
- // StringToDouble("0x1234") -> NaN // junk_string_value.
- // StringToDouble("01234") -> 668.0.
- // StringToDouble("") -> 0.0 // empty_string_value.
- // StringToDouble(" ") -> 0.0 // empty_string_value.
- // StringToDouble(" 1") -> 1.0
- // StringToDouble("0x") -> NaN // junk_string_value.
- // StringToDouble("0123e45") -> NaN // junk_string_value.
- // StringToDouble("01239E45") -> 1239e45.
- // StringToDouble("-infinity") -> NaN // junk_string_value.
- // StringToDouble("NaN") -> NaN // junk_string_value.
- //
- // flags = NO_FLAGS,
- // separator = ' ':
- // StringToDouble("1 2 3 4") -> 1234.0
- // StringToDouble("1 2") -> NaN // junk_string_value
- // StringToDouble("1 000 000.0") -> 1000000.0
- // StringToDouble("1.000 000") -> 1.0
- // StringToDouble("1.0e1 000") -> NaN // junk_string_value
- StringToDoubleConverter(int flags,
- double empty_string_value,
- double junk_string_value,
- const char* infinity_symbol,
- const char* nan_symbol,
- uc16 separator = kNoSeparator)
- : flags_(flags),
- empty_string_value_(empty_string_value),
- junk_string_value_(junk_string_value),
- infinity_symbol_(infinity_symbol),
- nan_symbol_(nan_symbol),
- separator_(separator) {
- }
-
- // Performs the conversion.
- // The output parameter 'processed_characters_count' is set to the number
- // of characters that have been processed to read the number.
- // Spaces than are processed with ALLOW_{LEADING|TRAILING}_SPACES are included
- // in the 'processed_characters_count'. Trailing junk is never included.
- double StringToDouble(const char* buffer,
- int length,
- int* processed_characters_count) const;
-
- // Same as StringToDouble above but for 16 bit characters.
- double StringToDouble(const uc16* buffer,
- int length,
- int* processed_characters_count) const;
-
- // Same as StringToDouble but reads a float.
- // Note that this is not equivalent to static_cast<float>(StringToDouble(...))
- // due to potential double-rounding.
- float StringToFloat(const char* buffer,
- int length,
- int* processed_characters_count) const;
-
- // Same as StringToFloat above but for 16 bit characters.
- float StringToFloat(const uc16* buffer,
- int length,
- int* processed_characters_count) const;
-
- private:
- const int flags_;
- const double empty_string_value_;
- const double junk_string_value_;
- const char* const infinity_symbol_;
- const char* const nan_symbol_;
- const uc16 separator_;
-
- template <class Iterator>
- double StringToIeee(Iterator start_pointer,
- int length,
- bool read_as_double,
- int* processed_characters_count) const;
-
- DOUBLE_CONVERSION_DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter);
-};
-
-} // namespace double_conversion
-
-// ICU PATCH: Close ICU namespace
-U_NAMESPACE_END
-
-#endif // DOUBLE_CONVERSION_STRING_TO_DOUBLE_H_
-#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
+// © 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 2012 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_STRING_TO_DOUBLE_H_
+#define DOUBLE_CONVERSION_STRING_TO_DOUBLE_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 {
+
+class StringToDoubleConverter {
+ public:
+ // Enumeration for allowing octals and ignoring junk when converting
+ // strings to numbers.
+ enum Flags {
+ NO_FLAGS = 0,
+ ALLOW_HEX = 1,
+ ALLOW_OCTALS = 2,
+ ALLOW_TRAILING_JUNK = 4,
+ ALLOW_LEADING_SPACES = 8,
+ ALLOW_TRAILING_SPACES = 16,
+ ALLOW_SPACES_AFTER_SIGN = 32,
+ ALLOW_CASE_INSENSITIVITY = 64,
+ ALLOW_CASE_INSENSIBILITY = 64, // Deprecated
+ ALLOW_HEX_FLOATS = 128,
+ };
+
+ static const uc16 kNoSeparator = '\0';
+
+ // Flags should be a bit-or combination of the possible Flags-enum.
+ // - NO_FLAGS: no special flags.
+ // - ALLOW_HEX: recognizes the prefix "0x". Hex numbers may only be integers.
+ // Ex: StringToDouble("0x1234") -> 4660.0
+ // In StringToDouble("0x1234.56") the characters ".56" are trailing
+ // junk. The result of the call is hence dependent on
+ // the ALLOW_TRAILING_JUNK flag and/or the junk value.
+ // With this flag "0x" is a junk-string. Even with ALLOW_TRAILING_JUNK,
+ // the string will not be parsed as "0" followed by junk.
+ //
+ // - ALLOW_OCTALS: recognizes the prefix "0" for octals:
+ // If a sequence of octal digits starts with '0', then the number is
+ // read as octal integer. Octal numbers may only be integers.
+ // Ex: StringToDouble("01234") -> 668.0
+ // StringToDouble("012349") -> 12349.0 // Not a sequence of octal
+ // // digits.
+ // In StringToDouble("01234.56") the characters ".56" are trailing
+ // junk. The result of the call is hence dependent on
+ // the ALLOW_TRAILING_JUNK flag and/or the junk value.
+ // In StringToDouble("01234e56") the characters "e56" are trailing
+ // junk, too.
+ // - ALLOW_TRAILING_JUNK: ignore trailing characters that are not part of
+ // a double literal.
+ // - ALLOW_LEADING_SPACES: skip over leading whitespace, including spaces,
+ // new-lines, and tabs.
+ // - ALLOW_TRAILING_SPACES: ignore trailing whitespace.
+ // - ALLOW_SPACES_AFTER_SIGN: ignore whitespace after the sign.
+ // Ex: StringToDouble("- 123.2") -> -123.2.
+ // StringToDouble("+ 123.2") -> 123.2
+ // - ALLOW_CASE_INSENSITIVITY: ignore case of characters for special values:
+ // infinity and nan.
+ // - ALLOW_HEX_FLOATS: allows hexadecimal float literals.
+ // This *must* start with "0x" and separate the exponent with "p".
+ // Examples: 0x1.2p3 == 9.0
+ // 0x10.1p0 == 16.0625
+ // ALLOW_HEX and ALLOW_HEX_FLOATS are indendent.
+ //
+ // empty_string_value is returned when an empty string is given as input.
+ // If ALLOW_LEADING_SPACES or ALLOW_TRAILING_SPACES are set, then a string
+ // containing only spaces is converted to the 'empty_string_value', too.
+ //
+ // junk_string_value is returned when
+ // a) ALLOW_TRAILING_JUNK is not set, and a junk character (a character not
+ // part of a double-literal) is found.
+ // b) ALLOW_TRAILING_JUNK is set, but the string does not start with a
+ // double literal.
+ //
+ // infinity_symbol and nan_symbol are strings that are used to detect
+ // inputs that represent infinity and NaN. They can be null, in which case
+ // they are ignored.
+ // The conversion routine first reads any possible signs. Then it compares the
+ // following character of the input-string with the first character of
+ // the infinity, and nan-symbol. If either matches, the function assumes, that
+ // a match has been found, and expects the following input characters to match
+ // the remaining characters of the special-value symbol.
+ // This means that the following restrictions apply to special-value symbols:
+ // - they must not start with signs ('+', or '-'),
+ // - they must not have the same first character.
+ // - they must not start with digits.
+ //
+ // If the separator character is not kNoSeparator, then that specific
+ // character is ignored when in between two valid digits of the significant.
+ // It is not allowed to appear in the exponent.
+ // It is not allowed to lead or trail the number.
+ // It is not allowed to appear twice next to each other.
+ //
+ // Examples:
+ // flags = ALLOW_HEX | ALLOW_TRAILING_JUNK,
+ // empty_string_value = 0.0,
+ // junk_string_value = NaN,
+ // infinity_symbol = "infinity",
+ // nan_symbol = "nan":
+ // StringToDouble("0x1234") -> 4660.0.
+ // StringToDouble("0x1234K") -> 4660.0.
+ // StringToDouble("") -> 0.0 // empty_string_value.
+ // StringToDouble(" ") -> NaN // junk_string_value.
+ // StringToDouble(" 1") -> NaN // junk_string_value.
+ // StringToDouble("0x") -> NaN // junk_string_value.
+ // StringToDouble("-123.45") -> -123.45.
+ // StringToDouble("--123.45") -> NaN // junk_string_value.
+ // StringToDouble("123e45") -> 123e45.
+ // StringToDouble("123E45") -> 123e45.
+ // StringToDouble("123e+45") -> 123e45.
+ // StringToDouble("123E-45") -> 123e-45.
+ // StringToDouble("123e") -> 123.0 // trailing junk ignored.
+ // StringToDouble("123e-") -> 123.0 // trailing junk ignored.
+ // StringToDouble("+NaN") -> NaN // NaN string literal.
+ // StringToDouble("-infinity") -> -inf. // infinity literal.
+ // StringToDouble("Infinity") -> NaN // junk_string_value.
+ //
+ // flags = ALLOW_OCTAL | ALLOW_LEADING_SPACES,
+ // empty_string_value = 0.0,
+ // junk_string_value = NaN,
+ // infinity_symbol = NULL,
+ // nan_symbol = NULL:
+ // StringToDouble("0x1234") -> NaN // junk_string_value.
+ // StringToDouble("01234") -> 668.0.
+ // StringToDouble("") -> 0.0 // empty_string_value.
+ // StringToDouble(" ") -> 0.0 // empty_string_value.
+ // StringToDouble(" 1") -> 1.0
+ // StringToDouble("0x") -> NaN // junk_string_value.
+ // StringToDouble("0123e45") -> NaN // junk_string_value.
+ // StringToDouble("01239E45") -> 1239e45.
+ // StringToDouble("-infinity") -> NaN // junk_string_value.
+ // StringToDouble("NaN") -> NaN // junk_string_value.
+ //
+ // flags = NO_FLAGS,
+ // separator = ' ':
+ // StringToDouble("1 2 3 4") -> 1234.0
+ // StringToDouble("1 2") -> NaN // junk_string_value
+ // StringToDouble("1 000 000.0") -> 1000000.0
+ // StringToDouble("1.000 000") -> 1.0
+ // StringToDouble("1.0e1 000") -> NaN // junk_string_value
+ StringToDoubleConverter(int flags,
+ double empty_string_value,
+ double junk_string_value,
+ const char* infinity_symbol,
+ const char* nan_symbol,
+ uc16 separator = kNoSeparator)
+ : flags_(flags),
+ empty_string_value_(empty_string_value),
+ junk_string_value_(junk_string_value),
+ infinity_symbol_(infinity_symbol),
+ nan_symbol_(nan_symbol),
+ separator_(separator) {
+ }
+
+ // Performs the conversion.
+ // The output parameter 'processed_characters_count' is set to the number
+ // of characters that have been processed to read the number.
+ // Spaces than are processed with ALLOW_{LEADING|TRAILING}_SPACES are included
+ // in the 'processed_characters_count'. Trailing junk is never included.
+ double StringToDouble(const char* buffer,
+ int length,
+ int* processed_characters_count) const;
+
+ // Same as StringToDouble above but for 16 bit characters.
+ double StringToDouble(const uc16* buffer,
+ int length,
+ int* processed_characters_count) const;
+
+ // Same as StringToDouble but reads a float.
+ // Note that this is not equivalent to static_cast<float>(StringToDouble(...))
+ // due to potential double-rounding.
+ float StringToFloat(const char* buffer,
+ int length,
+ int* processed_characters_count) const;
+
+ // Same as StringToFloat above but for 16 bit characters.
+ float StringToFloat(const uc16* buffer,
+ int length,
+ int* processed_characters_count) const;
+
+ private:
+ const int flags_;
+ const double empty_string_value_;
+ const double junk_string_value_;
+ const char* const infinity_symbol_;
+ const char* const nan_symbol_;
+ const uc16 separator_;
+
+ template <class Iterator>
+ double StringToIeee(Iterator start_pointer,
+ int length,
+ bool read_as_double,
+ int* processed_characters_count) const;
+
+ DOUBLE_CONVERSION_DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter);
+};
+
+} // namespace double_conversion
+
+// ICU PATCH: Close ICU namespace
+U_NAMESPACE_END
+
+#endif // DOUBLE_CONVERSION_STRING_TO_DOUBLE_H_
+#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
diff --git a/contrib/libs/icu/i18n/double-conversion-strtod.cpp b/contrib/libs/icu/i18n/double-conversion-strtod.cpp
index ee6377782b..9b7244337f 100644
--- a/contrib/libs/icu/i18n/double-conversion-strtod.cpp
+++ b/contrib/libs/icu/i18n/double-conversion-strtod.cpp
@@ -1,626 +1,626 @@
-// © 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 <climits>
-#include <cstdarg>
-
-// ICU PATCH: Customize header file paths for ICU.
-
-#include "double-conversion-bignum.h"
-#include "double-conversion-cached-powers.h"
-#include "double-conversion-ieee.h"
-#include "double-conversion-strtod.h"
-
-// ICU PATCH: Wrap in ICU namespace
-U_NAMESPACE_BEGIN
-
-namespace double_conversion {
-
-#if defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS)
-// 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;
-#endif // #if defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS)
-// 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 = DOUBLE_CONVERSION_UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF);
-
-
-#if defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS)
-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 = DOUBLE_CONVERSION_ARRAY_SIZE(exact_powers_of_ten);
-#endif // #if defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS)
-
-// 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<const char> TrimLeadingZeros(Vector<const char> buffer) {
- for (int i = 0; i < buffer.length(); i++) {
- if (buffer[i] != '0') {
- return buffer.SubVector(i, buffer.length());
- }
- }
- return Vector<const char>(buffer.start(), 0);
-}
-
-
-static Vector<const char> TrimTrailingZeros(Vector<const char> buffer) {
- for (int i = buffer.length() - 1; i >= 0; --i) {
- if (buffer[i] != '0') {
- return buffer.SubVector(0, i + 1);
- }
- }
- return Vector<const char>(buffer.start(), 0);
-}
-
-
-static void CutToMaxSignificantDigits(Vector<const char> 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'.
- DOUBLE_CONVERSION_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<const char> buffer, int exponent,
- char* buffer_copy_space, int space_size,
- Vector<const char>* trimmed, int* updated_exponent) {
- Vector<const char> left_trimmed = TrimLeadingZeros(buffer);
- Vector<const char> right_trimmed = TrimTrailingZeros(left_trimmed);
- exponent += left_trimmed.length() - right_trimmed.length();
- if (right_trimmed.length() > kMaxSignificantDecimalDigits) {
- (void) space_size; // Mark variable as used.
- DOUBLE_CONVERSION_ASSERT(space_size >= kMaxSignificantDecimalDigits);
- CutToMaxSignificantDigits(right_trimmed, exponent,
- buffer_copy_space, updated_exponent);
- *trimmed = Vector<const char>(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<const char> 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';
- DOUBLE_CONVERSION_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<const char> 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<const char> 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;
-#else
- 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<double>(ReadUint64(trimmed, &read_digits));
- DOUBLE_CONVERSION_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<double>(ReadUint64(trimmed, &read_digits));
- DOUBLE_CONVERSION_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<double>(ReadUint64(trimmed, &read_digits));
- DOUBLE_CONVERSION_ASSERT(read_digits == trimmed.length());
- *result *= exact_powers_of_ten[remaining_digits];
- *result *= exact_powers_of_ten[exponent - remaining_digits];
- return true;
- }
- }
- return false;
-#endif
-}
-
-
-// Returns 10^exponent as an exact DiyFp.
-// The given exponent must be in the range [1; kDecimalExponentDistance[.
-static DiyFp AdjustmentPowerOfTen(int exponent) {
- DOUBLE_CONVERSION_ASSERT(0 < exponent);
- DOUBLE_CONVERSION_ASSERT(exponent < PowersOfTenCache::kDecimalExponentDistance);
- // Simply hardcode the remaining powers for the given decimal exponent
- // distance.
- DOUBLE_CONVERSION_ASSERT(PowersOfTenCache::kDecimalExponentDistance == 8);
- switch (exponent) {
- case 1: return DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0xa0000000, 00000000), -60);
- case 2: return DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0xc8000000, 00000000), -57);
- case 3: return DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0xfa000000, 00000000), -54);
- case 4: return DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0x9c400000, 00000000), -50);
- case 5: return DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0xc3500000, 00000000), -47);
- case 6: return DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0xf4240000, 00000000), -44);
- case 7: return DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0x98968000, 00000000), -40);
- default:
- DOUBLE_CONVERSION_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<const char> 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();
-
- DOUBLE_CONVERSION_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.
- DOUBLE_CONVERSION_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.
- DOUBLE_CONVERSION_ASSERT(DiyFp::kSignificandSize == 64);
- DOUBLE_CONVERSION_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<const char> buffer,
- int exponent,
- DiyFp diy_fp) {
- DOUBLE_CONVERSION_ASSERT(buffer.length() + exponent <= kMaxDecimalPower + 1);
- DOUBLE_CONVERSION_ASSERT(buffer.length() + exponent > kMinDecimalPower);
- DOUBLE_CONVERSION_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...
- DOUBLE_CONVERSION_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<const char> 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;
-}
-
-#if U_DEBUG // needed for ICU only in debug mode
-static bool IsDigit(const char d) {
- return ('0' <= d) && (d <= '9');
-}
-
-static bool IsNonZeroDigit(const char d) {
- return ('1' <= d) && (d <= '9');
-}
-
-static bool AssertTrimmedDigits(const Vector<const char>& buffer) {
- for(int i = 0; i < buffer.length(); ++i) {
- if(!IsDigit(buffer[i])) {
- return false;
- }
- }
- return (buffer.length() == 0) || (IsNonZeroDigit(buffer[0]) && IsNonZeroDigit(buffer[buffer.length()-1]));
-}
-#endif // needed for ICU only in debug mode
-
-double StrtodTrimmed(Vector<const char> trimmed, int exponent) {
- DOUBLE_CONVERSION_ASSERT(trimmed.length() <= kMaxSignificantDecimalDigits);
- DOUBLE_CONVERSION_ASSERT(AssertTrimmedDigits(trimmed));
- double guess;
- const 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();
- }
-}
-
-double Strtod(Vector<const char> buffer, int exponent) {
- char copy_buffer[kMaxSignificantDecimalDigits];
- Vector<const char> trimmed;
- int updated_exponent;
- TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits,
- &trimmed, &updated_exponent);
- return StrtodTrimmed(trimmed, updated_exponent);
-}
-
-static float SanitizedDoubletof(double d) {
- DOUBLE_CONVERSION_ASSERT(d >= 0.0);
- // ASAN has a sanitize check that disallows casting doubles to floats if
- // they are too big.
- // https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#available-checks
- // The behavior should be covered by IEEE 754, but some projects use this
- // flag, so work around it.
- float max_finite = 3.4028234663852885981170418348451692544e+38;
- // The half-way point between the max-finite and infinity value.
- // Since infinity has an even significand everything equal or greater than
- // this value should become infinity.
- double half_max_finite_infinity =
- 3.40282356779733661637539395458142568448e+38;
- if (d >= max_finite) {
- if (d >= half_max_finite_infinity) {
- return Single::Infinity();
- } else {
- return max_finite;
- }
- } else {
- return static_cast<float>(d);
- }
-}
-
-float Strtof(Vector<const char> buffer, int exponent) {
- char copy_buffer[kMaxSignificantDecimalDigits];
- Vector<const char> 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 = SanitizedDoubletof(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 = SanitizedDoubletof(double_previous);
- float f2 = float_guess;
- float f3 = SanitizedDoubletof(double_next);
- float f4;
- if (is_correct) {
- f4 = f3;
- } else {
- double double_next2 = Double(double_next).NextDouble();
- f4 = SanitizedDoubletof(double_next2);
- }
- (void) f2; // Mark variable as used.
- DOUBLE_CONVERSION_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;
- }
-
- DOUBLE_CONVERSION_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 candidates (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<double>(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
+// © 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 <climits>
+#include <cstdarg>
+
+// ICU PATCH: Customize header file paths for ICU.
+
+#include "double-conversion-bignum.h"
+#include "double-conversion-cached-powers.h"
+#include "double-conversion-ieee.h"
+#include "double-conversion-strtod.h"
+
+// ICU PATCH: Wrap in ICU namespace
+U_NAMESPACE_BEGIN
+
+namespace double_conversion {
+
+#if defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS)
+// 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;
+#endif // #if defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS)
+// 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 = DOUBLE_CONVERSION_UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF);
+
+
+#if defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS)
+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 = DOUBLE_CONVERSION_ARRAY_SIZE(exact_powers_of_ten);
+#endif // #if defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS)
+
+// 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<const char> TrimLeadingZeros(Vector<const char> buffer) {
+ for (int i = 0; i < buffer.length(); i++) {
+ if (buffer[i] != '0') {
+ return buffer.SubVector(i, buffer.length());
+ }
+ }
+ return Vector<const char>(buffer.start(), 0);
+}
+
+
+static Vector<const char> TrimTrailingZeros(Vector<const char> buffer) {
+ for (int i = buffer.length() - 1; i >= 0; --i) {
+ if (buffer[i] != '0') {
+ return buffer.SubVector(0, i + 1);
+ }
+ }
+ return Vector<const char>(buffer.start(), 0);
+}
+
+
+static void CutToMaxSignificantDigits(Vector<const char> 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'.
+ DOUBLE_CONVERSION_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<const char> buffer, int exponent,
+ char* buffer_copy_space, int space_size,
+ Vector<const char>* trimmed, int* updated_exponent) {
+ Vector<const char> left_trimmed = TrimLeadingZeros(buffer);
+ Vector<const char> right_trimmed = TrimTrailingZeros(left_trimmed);
+ exponent += left_trimmed.length() - right_trimmed.length();
+ if (right_trimmed.length() > kMaxSignificantDecimalDigits) {
+ (void) space_size; // Mark variable as used.
+ DOUBLE_CONVERSION_ASSERT(space_size >= kMaxSignificantDecimalDigits);
+ CutToMaxSignificantDigits(right_trimmed, exponent,
+ buffer_copy_space, updated_exponent);
+ *trimmed = Vector<const char>(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<const char> 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';
+ DOUBLE_CONVERSION_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<const char> 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<const char> 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;
+#else
+ 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<double>(ReadUint64(trimmed, &read_digits));
+ DOUBLE_CONVERSION_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<double>(ReadUint64(trimmed, &read_digits));
+ DOUBLE_CONVERSION_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<double>(ReadUint64(trimmed, &read_digits));
+ DOUBLE_CONVERSION_ASSERT(read_digits == trimmed.length());
+ *result *= exact_powers_of_ten[remaining_digits];
+ *result *= exact_powers_of_ten[exponent - remaining_digits];
+ return true;
+ }
+ }
+ return false;
+#endif
+}
+
+
+// Returns 10^exponent as an exact DiyFp.
+// The given exponent must be in the range [1; kDecimalExponentDistance[.
+static DiyFp AdjustmentPowerOfTen(int exponent) {
+ DOUBLE_CONVERSION_ASSERT(0 < exponent);
+ DOUBLE_CONVERSION_ASSERT(exponent < PowersOfTenCache::kDecimalExponentDistance);
+ // Simply hardcode the remaining powers for the given decimal exponent
+ // distance.
+ DOUBLE_CONVERSION_ASSERT(PowersOfTenCache::kDecimalExponentDistance == 8);
+ switch (exponent) {
+ case 1: return DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0xa0000000, 00000000), -60);
+ case 2: return DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0xc8000000, 00000000), -57);
+ case 3: return DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0xfa000000, 00000000), -54);
+ case 4: return DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0x9c400000, 00000000), -50);
+ case 5: return DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0xc3500000, 00000000), -47);
+ case 6: return DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0xf4240000, 00000000), -44);
+ case 7: return DiyFp(DOUBLE_CONVERSION_UINT64_2PART_C(0x98968000, 00000000), -40);
+ default:
+ DOUBLE_CONVERSION_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<const char> 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();
+
+ DOUBLE_CONVERSION_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.
+ DOUBLE_CONVERSION_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.
+ DOUBLE_CONVERSION_ASSERT(DiyFp::kSignificandSize == 64);
+ DOUBLE_CONVERSION_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<const char> buffer,
+ int exponent,
+ DiyFp diy_fp) {
+ DOUBLE_CONVERSION_ASSERT(buffer.length() + exponent <= kMaxDecimalPower + 1);
+ DOUBLE_CONVERSION_ASSERT(buffer.length() + exponent > kMinDecimalPower);
+ DOUBLE_CONVERSION_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...
+ DOUBLE_CONVERSION_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<const char> 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;
+}
+
+#if U_DEBUG // needed for ICU only in debug mode
+static bool IsDigit(const char d) {
+ return ('0' <= d) && (d <= '9');
+}
+
+static bool IsNonZeroDigit(const char d) {
+ return ('1' <= d) && (d <= '9');
+}
+
+static bool AssertTrimmedDigits(const Vector<const char>& buffer) {
+ for(int i = 0; i < buffer.length(); ++i) {
+ if(!IsDigit(buffer[i])) {
+ return false;
+ }
+ }
+ return (buffer.length() == 0) || (IsNonZeroDigit(buffer[0]) && IsNonZeroDigit(buffer[buffer.length()-1]));
+}
+#endif // needed for ICU only in debug mode
+
+double StrtodTrimmed(Vector<const char> trimmed, int exponent) {
+ DOUBLE_CONVERSION_ASSERT(trimmed.length() <= kMaxSignificantDecimalDigits);
+ DOUBLE_CONVERSION_ASSERT(AssertTrimmedDigits(trimmed));
+ double guess;
+ const 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();
+ }
+}
+
+double Strtod(Vector<const char> buffer, int exponent) {
+ char copy_buffer[kMaxSignificantDecimalDigits];
+ Vector<const char> trimmed;
+ int updated_exponent;
+ TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits,
+ &trimmed, &updated_exponent);
+ return StrtodTrimmed(trimmed, updated_exponent);
+}
+
+static float SanitizedDoubletof(double d) {
+ DOUBLE_CONVERSION_ASSERT(d >= 0.0);
+ // ASAN has a sanitize check that disallows casting doubles to floats if
+ // they are too big.
+ // https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#available-checks
+ // The behavior should be covered by IEEE 754, but some projects use this
+ // flag, so work around it.
+ float max_finite = 3.4028234663852885981170418348451692544e+38;
+ // The half-way point between the max-finite and infinity value.
+ // Since infinity has an even significand everything equal or greater than
+ // this value should become infinity.
+ double half_max_finite_infinity =
+ 3.40282356779733661637539395458142568448e+38;
+ if (d >= max_finite) {
+ if (d >= half_max_finite_infinity) {
+ return Single::Infinity();
+ } else {
+ return max_finite;
+ }
+ } else {
+ return static_cast<float>(d);
+ }
+}
+
+float Strtof(Vector<const char> buffer, int exponent) {
+ char copy_buffer[kMaxSignificantDecimalDigits];
+ Vector<const char> 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 = SanitizedDoubletof(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 = SanitizedDoubletof(double_previous);
+ float f2 = float_guess;
+ float f3 = SanitizedDoubletof(double_next);
+ float f4;
+ if (is_correct) {
+ f4 = f3;
+ } else {
+ double double_next2 = Double(double_next).NextDouble();
+ f4 = SanitizedDoubletof(double_next2);
+ }
+ (void) f2; // Mark variable as used.
+ DOUBLE_CONVERSION_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;
+ }
+
+ DOUBLE_CONVERSION_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 candidates (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<double>(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/contrib/libs/icu/i18n/double-conversion-strtod.h b/contrib/libs/icu/i18n/double-conversion-strtod.h
index 50ef746401..871bff8da6 100644
--- a/contrib/libs/icu/i18n/double-conversion-strtod.h
+++ b/contrib/libs/icu/i18n/double-conversion-strtod.h
@@ -1,68 +1,68 @@
-// © 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<const char> 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<const char> buffer, int exponent);
-
-// For special use cases, the heart of the Strtod() function is also available
-// separately, it assumes that 'trimmed' is as produced by TrimAndCut(), i.e.
-// no leading or trailing zeros, also no lone zero, and not 'too many' digits.
-double StrtodTrimmed(Vector<const char> trimmed, 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
+// © 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<const char> 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<const char> buffer, int exponent);
+
+// For special use cases, the heart of the Strtod() function is also available
+// separately, it assumes that 'trimmed' is as produced by TrimAndCut(), i.e.
+// no leading or trailing zeros, also no lone zero, and not 'too many' digits.
+double StrtodTrimmed(Vector<const char> trimmed, 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/contrib/libs/icu/i18n/double-conversion-utils.h b/contrib/libs/icu/i18n/double-conversion-utils.h
index 8c6a0e16e0..1e2647b9d6 100644
--- a/contrib/libs/icu/i18n/double-conversion-utils.h
+++ b/contrib/libs/icu/i18n/double-conversion-utils.h
@@ -1,389 +1,389 @@
-// © 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_UTILS_H_
-#define DOUBLE_CONVERSION_UTILS_H_
-
-#include <cstdlib>
-#include <cstring>
-
-// ICU PATCH: Use U_ASSERT instead of <assert.h>
-#include "uassert.h"
-#ifndef DOUBLE_CONVERSION_ASSERT
-#define DOUBLE_CONVERSION_ASSERT(condition) \
- U_ASSERT(condition);
-#endif
-#ifndef DOUBLE_CONVERSION_UNIMPLEMENTED
-#define DOUBLE_CONVERSION_UNIMPLEMENTED() (abort())
-#endif
-#ifndef DOUBLE_CONVERSION_NO_RETURN
-#ifdef _MSC_VER
-#define DOUBLE_CONVERSION_NO_RETURN __declspec(noreturn)
-#else
-#define DOUBLE_CONVERSION_NO_RETURN __attribute__((noreturn))
-#endif
-#endif
-#ifndef DOUBLE_CONVERSION_UNREACHABLE
-#ifdef _MSC_VER
-void DOUBLE_CONVERSION_NO_RETURN abort_noreturn();
-inline void abort_noreturn() { abort(); }
-#define DOUBLE_CONVERSION_UNREACHABLE() (abort_noreturn())
-#else
-#define DOUBLE_CONVERSION_UNREACHABLE() (abort())
-#endif
-#endif
-
-// Not all compilers support __has_attribute and combining a check for both
-// ifdef and __has_attribute on the same preprocessor line isn't portable.
-#ifdef __has_attribute
-# define DOUBLE_CONVERSION_HAS_ATTRIBUTE(x) __has_attribute(x)
-#else
-# define DOUBLE_CONVERSION_HAS_ATTRIBUTE(x) 0
-#endif
-
-#ifndef DOUBLE_CONVERSION_UNUSED
-#if DOUBLE_CONVERSION_HAS_ATTRIBUTE(unused)
-#define DOUBLE_CONVERSION_UNUSED __attribute__((unused))
-#else
-#define DOUBLE_CONVERSION_UNUSED
-#endif
-#endif
-
-#if DOUBLE_CONVERSION_HAS_ATTRIBUTE(uninitialized)
-#define DOUBLE_CONVERSION_STACK_UNINITIALIZED __attribute__((uninitialized))
-#else
-#define DOUBLE_CONVERSION_STACK_UNINITIALIZED
-#endif
-
-// Double operations detection based on target architecture.
-// Linux uses a 80bit wide floating point stack on x86. This induces double
-// rounding, which in turn leads to wrong results.
-// An easy way to test if the floating-point operations are correct is to
-// evaluate: 89255.0/1e22. If the floating-point stack is 64 bits wide then
-// the result is equal to 89255e-22.
-// The best way to test this, is to create a division-function and to compare
-// the output of the division with the expected result. (Inlining must be
-// disabled.)
-// On Linux,x86 89255e-22 != Div_double(89255.0/1e22)
-//
-// For example:
-/*
-// -- in div.c
-double Div_double(double x, double y) { return x / y; }
-
-// -- in main.c
-double Div_double(double x, double y); // Forward declaration.
-
-int main(int argc, char** argv) {
- return Div_double(89255.0, 1e22) == 89255e-22;
-}
-*/
-// Run as follows ./main || echo "correct"
-//
-// If it prints "correct" then the architecture should be here, in the "correct" section.
-#if defined(_M_X64) || defined(__x86_64__) || \
- defined(__ARMEL__) || defined(__avr32__) || defined(_M_ARM) || defined(_M_ARM64) || \
- defined(__hppa__) || defined(__ia64__) || \
- defined(__mips__) || \
- defined(__nios2__) || \
- defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \
- defined(_POWER) || defined(_ARCH_PPC) || defined(_ARCH_PPC64) || \
- defined(__sparc__) || defined(__sparc) || defined(__s390__) || \
- defined(__SH4__) || defined(__alpha__) || \
- defined(_MIPS_ARCH_MIPS32R2) || defined(__ARMEB__) ||\
- defined(__AARCH64EL__) || defined(__aarch64__) || defined(__AARCH64EB__) || \
- defined(__riscv) || defined(__e2k__) || \
- defined(__or1k__) || defined(__arc__) || \
- defined(__microblaze__) || defined(__XTENSA__) || \
- defined(__EMSCRIPTEN__) || defined(__wasm32__)
-#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
-#elif defined(__mc68000__) || \
- defined(__pnacl__) || defined(__native_client__)
-#undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS
-#elif defined(_M_IX86) || defined(__i386__) || defined(__i386)
-#if defined(_WIN32)
-// Windows uses a 64bit wide floating point stack.
-#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
-#else
-#undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS
-#endif // _WIN32
-#else
-#error Target architecture was not detected as supported by Double-Conversion.
-#endif
-
-#if defined(_WIN32) && !defined(__MINGW32__)
-
-typedef signed char int8_t;
-typedef unsigned char uint8_t;
-typedef short int16_t; // NOLINT
-typedef unsigned short uint16_t; // NOLINT
-typedef int int32_t;
-typedef unsigned int uint32_t;
-typedef __int64 int64_t;
-typedef unsigned __int64 uint64_t;
-// intptr_t and friends are defined in crtdefs.h through stdio.h.
-
-#else
-
-#include <stdint.h>
-
-#endif
-
-typedef uint16_t uc16;
-
-// The following macro works on both 32 and 64-bit platforms.
-// Usage: instead of writing 0x1234567890123456
-// write DOUBLE_CONVERSION_UINT64_2PART_C(0x12345678,90123456);
-#define DOUBLE_CONVERSION_UINT64_2PART_C(a, b) (((static_cast<uint64_t>(a) << 32) + 0x##b##u))
-
-
-// The expression DOUBLE_CONVERSION_ARRAY_SIZE(a) is a compile-time constant of type
-// size_t which represents the number of elements of the given
-// array. You should only use DOUBLE_CONVERSION_ARRAY_SIZE on statically allocated
-// arrays.
-#ifndef DOUBLE_CONVERSION_ARRAY_SIZE
-#define DOUBLE_CONVERSION_ARRAY_SIZE(a) \
- ((sizeof(a) / sizeof(*(a))) / \
- static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
-#endif
-
-// A macro to disallow the evil copy constructor and operator= functions
-// This should be used in the private: declarations for a class
-#ifndef DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN
-#define DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN(TypeName) \
- TypeName(const TypeName&); \
- void operator=(const TypeName&)
-#endif
-
-// A macro to disallow all the implicit constructors, namely the
-// default constructor, copy constructor and operator= functions.
-//
-// This should be used in the private: declarations for a class
-// that wants to prevent anyone from instantiating it. This is
-// especially useful for classes containing only static methods.
-#ifndef DOUBLE_CONVERSION_DISALLOW_IMPLICIT_CONSTRUCTORS
-#define DOUBLE_CONVERSION_DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
- TypeName(); \
- DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN(TypeName)
-#endif
-
-// ICU PATCH: Wrap in ICU namespace
-U_NAMESPACE_BEGIN
-
-namespace double_conversion {
-
-inline int StrLength(const char* string) {
- size_t length = strlen(string);
- DOUBLE_CONVERSION_ASSERT(length == static_cast<size_t>(static_cast<int>(length)));
- return static_cast<int>(length);
-}
-
-// This is a simplified version of V8's Vector class.
-template <typename T>
-class Vector {
- public:
- Vector() : start_(NULL), length_(0) {}
- Vector(T* data, int len) : start_(data), length_(len) {
- DOUBLE_CONVERSION_ASSERT(len == 0 || (len > 0 && data != NULL));
- }
-
- // Returns a vector using the same backing storage as this one,
- // spanning from and including 'from', to but not including 'to'.
- Vector<T> SubVector(int from, int to) {
- DOUBLE_CONVERSION_ASSERT(to <= length_);
- DOUBLE_CONVERSION_ASSERT(from < to);
- DOUBLE_CONVERSION_ASSERT(0 <= from);
- return Vector<T>(start() + from, to - from);
- }
-
- // Returns the length of the vector.
- int length() const { return length_; }
-
- // Returns whether or not the vector is empty.
- bool is_empty() const { return length_ == 0; }
-
- // Returns the pointer to the start of the data in the vector.
- T* start() const { return start_; }
-
- // Access individual vector elements - checks bounds in debug mode.
- T& operator[](int index) const {
- DOUBLE_CONVERSION_ASSERT(0 <= index && index < length_);
- return start_[index];
- }
-
- T& first() { return start_[0]; }
-
- T& last() { return start_[length_ - 1]; }
-
- void pop_back() {
- DOUBLE_CONVERSION_ASSERT(!is_empty());
- --length_;
- }
-
- private:
- T* start_;
- int length_;
-};
-
-
-// Helper class for building result strings in a character buffer. The
-// purpose of the class is to use safe operations that checks the
-// buffer bounds on all operations in debug mode.
-class StringBuilder {
- public:
- StringBuilder(char* buffer, int buffer_size)
- : buffer_(buffer, buffer_size), position_(0) { }
-
- ~StringBuilder() { if (!is_finalized()) Finalize(); }
-
- int size() const { return buffer_.length(); }
-
- // Get the current position in the builder.
- int position() const {
- DOUBLE_CONVERSION_ASSERT(!is_finalized());
- return position_;
- }
-
- // Reset the position.
- void Reset() { position_ = 0; }
-
- // Add a single character to the builder. It is not allowed to add
- // 0-characters; use the Finalize() method to terminate the string
- // instead.
- void AddCharacter(char c) {
- DOUBLE_CONVERSION_ASSERT(c != '\0');
- DOUBLE_CONVERSION_ASSERT(!is_finalized() && position_ < buffer_.length());
- buffer_[position_++] = c;
- }
-
- // Add an entire string to the builder. Uses strlen() internally to
- // compute the length of the input string.
- void AddString(const char* s) {
- AddSubstring(s, StrLength(s));
- }
-
- // Add the first 'n' characters of the given string 's' to the
- // builder. The input string must have enough characters.
- void AddSubstring(const char* s, int n) {
- DOUBLE_CONVERSION_ASSERT(!is_finalized() && position_ + n < buffer_.length());
- DOUBLE_CONVERSION_ASSERT(static_cast<size_t>(n) <= strlen(s));
- memmove(&buffer_[position_], s, n);
- position_ += n;
- }
-
-
- // Add character padding to the builder. If count is non-positive,
- // nothing is added to the builder.
- void AddPadding(char c, int count) {
- for (int i = 0; i < count; i++) {
- AddCharacter(c);
- }
- }
-
- // Finalize the string by 0-terminating it and returning the buffer.
- char* Finalize() {
- DOUBLE_CONVERSION_ASSERT(!is_finalized() && position_ < buffer_.length());
- buffer_[position_] = '\0';
- // Make sure nobody managed to add a 0-character to the
- // buffer while building the string.
- DOUBLE_CONVERSION_ASSERT(strlen(buffer_.start()) == static_cast<size_t>(position_));
- position_ = -1;
- DOUBLE_CONVERSION_ASSERT(is_finalized());
- return buffer_.start();
- }
-
- private:
- Vector<char> buffer_;
- int position_;
-
- bool is_finalized() const { return position_ < 0; }
-
- DOUBLE_CONVERSION_DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);
-};
-
-// The type-based aliasing rule allows the compiler to assume that pointers of
-// different types (for some definition of different) never alias each other.
-// Thus the following code does not work:
-//
-// float f = foo();
-// int fbits = *(int*)(&f);
-//
-// The compiler 'knows' that the int pointer can't refer to f since the types
-// don't match, so the compiler may cache f in a register, leaving random data
-// in fbits. Using C++ style casts makes no difference, however a pointer to
-// char data is assumed to alias any other pointer. This is the 'memcpy
-// exception'.
-//
-// Bit_cast uses the memcpy exception to move the bits from a variable of one
-// type of a variable of another type. Of course the end result is likely to
-// be implementation dependent. Most compilers (gcc-4.2 and MSVC 2005)
-// will completely optimize BitCast away.
-//
-// There is an additional use for BitCast.
-// Recent gccs will warn when they see casts that may result in breakage due to
-// the type-based aliasing rule. If you have checked that there is no breakage
-// you can use BitCast to cast one pointer type to another. This confuses gcc
-// enough that it can no longer see that you have cast one pointer type to
-// another thus avoiding the warning.
-template <class Dest, class Source>
-Dest BitCast(const Source& source) {
- // Compile time assertion: sizeof(Dest) == sizeof(Source)
- // A compile error here means your Dest and Source have different sizes.
-#if __cplusplus >= 201103L
- static_assert(sizeof(Dest) == sizeof(Source),
- "source and destination size mismatch");
-#else
- DOUBLE_CONVERSION_UNUSED
- typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1];
-#endif
-
- Dest dest;
- memmove(&dest, &source, sizeof(dest));
- return dest;
-}
-
-template <class Dest, class Source>
-Dest BitCast(Source* source) {
- return BitCast<Dest>(reinterpret_cast<uintptr_t>(source));
-}
-
-} // namespace double_conversion
-
-// ICU PATCH: Close ICU namespace
-U_NAMESPACE_END
-
-#endif // DOUBLE_CONVERSION_UTILS_H_
-#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
+// © 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_UTILS_H_
+#define DOUBLE_CONVERSION_UTILS_H_
+
+#include <cstdlib>
+#include <cstring>
+
+// ICU PATCH: Use U_ASSERT instead of <assert.h>
+#include "uassert.h"
+#ifndef DOUBLE_CONVERSION_ASSERT
+#define DOUBLE_CONVERSION_ASSERT(condition) \
+ U_ASSERT(condition);
+#endif
+#ifndef DOUBLE_CONVERSION_UNIMPLEMENTED
+#define DOUBLE_CONVERSION_UNIMPLEMENTED() (abort())
+#endif
+#ifndef DOUBLE_CONVERSION_NO_RETURN
+#ifdef _MSC_VER
+#define DOUBLE_CONVERSION_NO_RETURN __declspec(noreturn)
+#else
+#define DOUBLE_CONVERSION_NO_RETURN __attribute__((noreturn))
+#endif
+#endif
+#ifndef DOUBLE_CONVERSION_UNREACHABLE
+#ifdef _MSC_VER
+void DOUBLE_CONVERSION_NO_RETURN abort_noreturn();
+inline void abort_noreturn() { abort(); }
+#define DOUBLE_CONVERSION_UNREACHABLE() (abort_noreturn())
+#else
+#define DOUBLE_CONVERSION_UNREACHABLE() (abort())
+#endif
+#endif
+
+// Not all compilers support __has_attribute and combining a check for both
+// ifdef and __has_attribute on the same preprocessor line isn't portable.
+#ifdef __has_attribute
+# define DOUBLE_CONVERSION_HAS_ATTRIBUTE(x) __has_attribute(x)
+#else
+# define DOUBLE_CONVERSION_HAS_ATTRIBUTE(x) 0
+#endif
+
+#ifndef DOUBLE_CONVERSION_UNUSED
+#if DOUBLE_CONVERSION_HAS_ATTRIBUTE(unused)
+#define DOUBLE_CONVERSION_UNUSED __attribute__((unused))
+#else
+#define DOUBLE_CONVERSION_UNUSED
+#endif
+#endif
+
+#if DOUBLE_CONVERSION_HAS_ATTRIBUTE(uninitialized)
+#define DOUBLE_CONVERSION_STACK_UNINITIALIZED __attribute__((uninitialized))
+#else
+#define DOUBLE_CONVERSION_STACK_UNINITIALIZED
+#endif
+
+// Double operations detection based on target architecture.
+// Linux uses a 80bit wide floating point stack on x86. This induces double
+// rounding, which in turn leads to wrong results.
+// An easy way to test if the floating-point operations are correct is to
+// evaluate: 89255.0/1e22. If the floating-point stack is 64 bits wide then
+// the result is equal to 89255e-22.
+// The best way to test this, is to create a division-function and to compare
+// the output of the division with the expected result. (Inlining must be
+// disabled.)
+// On Linux,x86 89255e-22 != Div_double(89255.0/1e22)
+//
+// For example:
+/*
+// -- in div.c
+double Div_double(double x, double y) { return x / y; }
+
+// -- in main.c
+double Div_double(double x, double y); // Forward declaration.
+
+int main(int argc, char** argv) {
+ return Div_double(89255.0, 1e22) == 89255e-22;
+}
+*/
+// Run as follows ./main || echo "correct"
+//
+// If it prints "correct" then the architecture should be here, in the "correct" section.
+#if defined(_M_X64) || defined(__x86_64__) || \
+ defined(__ARMEL__) || defined(__avr32__) || defined(_M_ARM) || defined(_M_ARM64) || \
+ defined(__hppa__) || defined(__ia64__) || \
+ defined(__mips__) || \
+ defined(__nios2__) || \
+ defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \
+ defined(_POWER) || defined(_ARCH_PPC) || defined(_ARCH_PPC64) || \
+ defined(__sparc__) || defined(__sparc) || defined(__s390__) || \
+ defined(__SH4__) || defined(__alpha__) || \
+ defined(_MIPS_ARCH_MIPS32R2) || defined(__ARMEB__) ||\
+ defined(__AARCH64EL__) || defined(__aarch64__) || defined(__AARCH64EB__) || \
+ defined(__riscv) || defined(__e2k__) || \
+ defined(__or1k__) || defined(__arc__) || \
+ defined(__microblaze__) || defined(__XTENSA__) || \
+ defined(__EMSCRIPTEN__) || defined(__wasm32__)
+#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
+#elif defined(__mc68000__) || \
+ defined(__pnacl__) || defined(__native_client__)
+#undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS
+#elif defined(_M_IX86) || defined(__i386__) || defined(__i386)
+#if defined(_WIN32)
+// Windows uses a 64bit wide floating point stack.
+#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
+#else
+#undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS
+#endif // _WIN32
+#else
+#error Target architecture was not detected as supported by Double-Conversion.
+#endif
+
+#if defined(_WIN32) && !defined(__MINGW32__)
+
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef short int16_t; // NOLINT
+typedef unsigned short uint16_t; // NOLINT
+typedef int int32_t;
+typedef unsigned int uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+// intptr_t and friends are defined in crtdefs.h through stdio.h.
+
+#else
+
+#include <stdint.h>
+
+#endif
+
+typedef uint16_t uc16;
+
+// The following macro works on both 32 and 64-bit platforms.
+// Usage: instead of writing 0x1234567890123456
+// write DOUBLE_CONVERSION_UINT64_2PART_C(0x12345678,90123456);
+#define DOUBLE_CONVERSION_UINT64_2PART_C(a, b) (((static_cast<uint64_t>(a) << 32) + 0x##b##u))
+
+
+// The expression DOUBLE_CONVERSION_ARRAY_SIZE(a) is a compile-time constant of type
+// size_t which represents the number of elements of the given
+// array. You should only use DOUBLE_CONVERSION_ARRAY_SIZE on statically allocated
+// arrays.
+#ifndef DOUBLE_CONVERSION_ARRAY_SIZE
+#define DOUBLE_CONVERSION_ARRAY_SIZE(a) \
+ ((sizeof(a) / sizeof(*(a))) / \
+ static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
+#endif
+
+// A macro to disallow the evil copy constructor and operator= functions
+// This should be used in the private: declarations for a class
+#ifndef DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN
+#define DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&); \
+ void operator=(const TypeName&)
+#endif
+
+// A macro to disallow all the implicit constructors, namely the
+// default constructor, copy constructor and operator= functions.
+//
+// This should be used in the private: declarations for a class
+// that wants to prevent anyone from instantiating it. This is
+// especially useful for classes containing only static methods.
+#ifndef DOUBLE_CONVERSION_DISALLOW_IMPLICIT_CONSTRUCTORS
+#define DOUBLE_CONVERSION_DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+ TypeName(); \
+ DOUBLE_CONVERSION_DISALLOW_COPY_AND_ASSIGN(TypeName)
+#endif
+
+// ICU PATCH: Wrap in ICU namespace
+U_NAMESPACE_BEGIN
+
+namespace double_conversion {
+
+inline int StrLength(const char* string) {
+ size_t length = strlen(string);
+ DOUBLE_CONVERSION_ASSERT(length == static_cast<size_t>(static_cast<int>(length)));
+ return static_cast<int>(length);
+}
+
+// This is a simplified version of V8's Vector class.
+template <typename T>
+class Vector {
+ public:
+ Vector() : start_(NULL), length_(0) {}
+ Vector(T* data, int len) : start_(data), length_(len) {
+ DOUBLE_CONVERSION_ASSERT(len == 0 || (len > 0 && data != NULL));
+ }
+
+ // Returns a vector using the same backing storage as this one,
+ // spanning from and including 'from', to but not including 'to'.
+ Vector<T> SubVector(int from, int to) {
+ DOUBLE_CONVERSION_ASSERT(to <= length_);
+ DOUBLE_CONVERSION_ASSERT(from < to);
+ DOUBLE_CONVERSION_ASSERT(0 <= from);
+ return Vector<T>(start() + from, to - from);
+ }
+
+ // Returns the length of the vector.
+ int length() const { return length_; }
+
+ // Returns whether or not the vector is empty.
+ bool is_empty() const { return length_ == 0; }
+
+ // Returns the pointer to the start of the data in the vector.
+ T* start() const { return start_; }
+
+ // Access individual vector elements - checks bounds in debug mode.
+ T& operator[](int index) const {
+ DOUBLE_CONVERSION_ASSERT(0 <= index && index < length_);
+ return start_[index];
+ }
+
+ T& first() { return start_[0]; }
+
+ T& last() { return start_[length_ - 1]; }
+
+ void pop_back() {
+ DOUBLE_CONVERSION_ASSERT(!is_empty());
+ --length_;
+ }
+
+ private:
+ T* start_;
+ int length_;
+};
+
+
+// Helper class for building result strings in a character buffer. The
+// purpose of the class is to use safe operations that checks the
+// buffer bounds on all operations in debug mode.
+class StringBuilder {
+ public:
+ StringBuilder(char* buffer, int buffer_size)
+ : buffer_(buffer, buffer_size), position_(0) { }
+
+ ~StringBuilder() { if (!is_finalized()) Finalize(); }
+
+ int size() const { return buffer_.length(); }
+
+ // Get the current position in the builder.
+ int position() const {
+ DOUBLE_CONVERSION_ASSERT(!is_finalized());
+ return position_;
+ }
+
+ // Reset the position.
+ void Reset() { position_ = 0; }
+
+ // Add a single character to the builder. It is not allowed to add
+ // 0-characters; use the Finalize() method to terminate the string
+ // instead.
+ void AddCharacter(char c) {
+ DOUBLE_CONVERSION_ASSERT(c != '\0');
+ DOUBLE_CONVERSION_ASSERT(!is_finalized() && position_ < buffer_.length());
+ buffer_[position_++] = c;
+ }
+
+ // Add an entire string to the builder. Uses strlen() internally to
+ // compute the length of the input string.
+ void AddString(const char* s) {
+ AddSubstring(s, StrLength(s));
+ }
+
+ // Add the first 'n' characters of the given string 's' to the
+ // builder. The input string must have enough characters.
+ void AddSubstring(const char* s, int n) {
+ DOUBLE_CONVERSION_ASSERT(!is_finalized() && position_ + n < buffer_.length());
+ DOUBLE_CONVERSION_ASSERT(static_cast<size_t>(n) <= strlen(s));
+ memmove(&buffer_[position_], s, n);
+ position_ += n;
+ }
+
+
+ // Add character padding to the builder. If count is non-positive,
+ // nothing is added to the builder.
+ void AddPadding(char c, int count) {
+ for (int i = 0; i < count; i++) {
+ AddCharacter(c);
+ }
+ }
+
+ // Finalize the string by 0-terminating it and returning the buffer.
+ char* Finalize() {
+ DOUBLE_CONVERSION_ASSERT(!is_finalized() && position_ < buffer_.length());
+ buffer_[position_] = '\0';
+ // Make sure nobody managed to add a 0-character to the
+ // buffer while building the string.
+ DOUBLE_CONVERSION_ASSERT(strlen(buffer_.start()) == static_cast<size_t>(position_));
+ position_ = -1;
+ DOUBLE_CONVERSION_ASSERT(is_finalized());
+ return buffer_.start();
+ }
+
+ private:
+ Vector<char> buffer_;
+ int position_;
+
+ bool is_finalized() const { return position_ < 0; }
+
+ DOUBLE_CONVERSION_DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);
+};
+
+// The type-based aliasing rule allows the compiler to assume that pointers of
+// different types (for some definition of different) never alias each other.
+// Thus the following code does not work:
+//
+// float f = foo();
+// int fbits = *(int*)(&f);
+//
+// The compiler 'knows' that the int pointer can't refer to f since the types
+// don't match, so the compiler may cache f in a register, leaving random data
+// in fbits. Using C++ style casts makes no difference, however a pointer to
+// char data is assumed to alias any other pointer. This is the 'memcpy
+// exception'.
+//
+// Bit_cast uses the memcpy exception to move the bits from a variable of one
+// type of a variable of another type. Of course the end result is likely to
+// be implementation dependent. Most compilers (gcc-4.2 and MSVC 2005)
+// will completely optimize BitCast away.
+//
+// There is an additional use for BitCast.
+// Recent gccs will warn when they see casts that may result in breakage due to
+// the type-based aliasing rule. If you have checked that there is no breakage
+// you can use BitCast to cast one pointer type to another. This confuses gcc
+// enough that it can no longer see that you have cast one pointer type to
+// another thus avoiding the warning.
+template <class Dest, class Source>
+Dest BitCast(const Source& source) {
+ // Compile time assertion: sizeof(Dest) == sizeof(Source)
+ // A compile error here means your Dest and Source have different sizes.
+#if __cplusplus >= 201103L
+ static_assert(sizeof(Dest) == sizeof(Source),
+ "source and destination size mismatch");
+#else
+ DOUBLE_CONVERSION_UNUSED
+ typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1];
+#endif
+
+ Dest dest;
+ memmove(&dest, &source, sizeof(dest));
+ return dest;
+}
+
+template <class Dest, class Source>
+Dest BitCast(Source* source) {
+ return BitCast<Dest>(reinterpret_cast<uintptr_t>(source));
+}
+
+} // namespace double_conversion
+
+// ICU PATCH: Close ICU namespace
+U_NAMESPACE_END
+
+#endif // DOUBLE_CONVERSION_UTILS_H_
+#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
diff --git a/contrib/libs/icu/i18n/double-conversion.h b/contrib/libs/icu/i18n/double-conversion.h
index eddc38763b..b789a64847 100644
--- a/contrib/libs/icu/i18n/double-conversion.h
+++ b/contrib/libs/icu/i18n/double-conversion.h
@@ -1,46 +1,46 @@
-// © 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 2012 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_DOUBLE_CONVERSION_H_
-#define DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_
-
-// ICU PATCH: Customize header file paths for ICU.
-
-#include "double-conversion-string-to-double.h"
-#include "double-conversion-double-to-string.h"
-
-#endif // DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_
-#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
+// © 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 2012 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_DOUBLE_CONVERSION_H_
+#define DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_
+
+// ICU PATCH: Customize header file paths for ICU.
+
+#include "double-conversion-string-to-double.h"
+#include "double-conversion-double-to-string.h"
+
+#endif // DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_
+#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
diff --git a/contrib/libs/icu/i18n/dt_impl.h b/contrib/libs/icu/i18n/dt_impl.h
index a4058c6924..27b21487ad 100644
--- a/contrib/libs/icu/i18n/dt_impl.h
+++ b/contrib/libs/icu/i18n/dt_impl.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/dtfmtsym.cpp b/contrib/libs/icu/i18n/dtfmtsym.cpp
index 690f6a4cae..2ddc516727 100644
--- a/contrib/libs/icu/i18n/dtfmtsym.cpp
+++ b/contrib/libs/icu/i18n/dtfmtsym.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -21,9 +21,9 @@
* 10/12/05 emmons Added setters for eraNames, month/day by width/context
*******************************************************************************
*/
-
-#include <utility>
-
+
+#include <utility>
+
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
@@ -1246,7 +1246,7 @@ const UnicodeString**
DateFormatSymbols::getZoneStrings(int32_t& rowCount, int32_t& columnCount) const
{
const UnicodeString **result = NULL;
- static UMutex LOCK;
+ static UMutex LOCK;
umtx_lock(&LOCK);
if (fZoneStrings == NULL) {
@@ -1313,7 +1313,7 @@ DateFormatSymbols::initZoneStringsArray(void) {
UDate now = Calendar::getNow();
UnicodeString tzDispName;
- while ((tzid = tzids->snext(status)) != 0) {
+ while ((tzid = tzids->snext(status)) != 0) {
if (U_FAILURE(status)) {
break;
}
@@ -1370,7 +1370,7 @@ DateFormatSymbols::setZoneStrings(const UnicodeString* const *strings, int32_t r
//------------------------------------------------------
-const char16_t * U_EXPORT2
+const char16_t * U_EXPORT2
DateFormatSymbols::getPatternUChars(void)
{
return gPatternChars;
@@ -1502,7 +1502,7 @@ struct CalendarDataSink : public ResourceSink {
* To avoid double deletion, 'maps' won't take ownership of the objects. Instead,
* 'mapRefs' will own them and will delete them when CalendarDataSink is deleted.
*/
- MemoryPool<Hashtable> mapRefs;
+ MemoryPool<Hashtable> mapRefs;
// Paths and the aliases they point to
UVector aliasPathPairs;
@@ -1520,7 +1520,7 @@ struct CalendarDataSink : public ResourceSink {
// Initializes CalendarDataSink with default values
CalendarDataSink(UErrorCode& status)
: arrays(FALSE, status), arraySizes(FALSE, status), maps(FALSE, status),
- mapRefs(),
+ mapRefs(),
aliasPathPairs(uprv_deleteUObject, uhash_compareUnicodeString, status),
currentCalendarType(), nextCalendarType(),
resourcesToVisit(NULL), aliasRelativePath() {
@@ -1633,23 +1633,23 @@ struct CalendarDataSink : public ResourceSink {
Hashtable *aliasMap;
if ((aliasArray = (UnicodeString*)arrays.get(*alias)) != NULL) {
UnicodeString *path = (UnicodeString*)aliasPathPairs[i + 1];
- if (arrays.get(*path) == NULL) {
- // Clone the array
- int32_t aliasArraySize = arraySizes.geti(*alias);
- LocalArray<UnicodeString> aliasArrayCopy(new UnicodeString[aliasArraySize], errorCode);
- if (U_FAILURE(errorCode)) { return; }
- uprv_arrayCopy(aliasArray, aliasArrayCopy.getAlias(), aliasArraySize);
- // Put the array on the 'arrays' map
- arrays.put(*path, aliasArrayCopy.orphan(), errorCode);
- arraySizes.puti(*path, aliasArraySize, errorCode);
- }
+ if (arrays.get(*path) == NULL) {
+ // Clone the array
+ int32_t aliasArraySize = arraySizes.geti(*alias);
+ LocalArray<UnicodeString> aliasArrayCopy(new UnicodeString[aliasArraySize], errorCode);
+ if (U_FAILURE(errorCode)) { return; }
+ uprv_arrayCopy(aliasArray, aliasArrayCopy.getAlias(), aliasArraySize);
+ // Put the array on the 'arrays' map
+ arrays.put(*path, aliasArrayCopy.orphan(), errorCode);
+ arraySizes.puti(*path, aliasArraySize, errorCode);
+ }
if (U_FAILURE(errorCode)) { return; }
mod = true;
} else if ((aliasMap = (Hashtable*)maps.get(*alias)) != NULL) {
UnicodeString *path = (UnicodeString*)aliasPathPairs[i + 1];
- if (maps.get(*path) == NULL) {
- maps.put(*path, aliasMap, errorCode);
- }
+ if (maps.get(*path) == NULL) {
+ maps.put(*path, aliasMap, errorCode);
+ }
if (U_FAILURE(errorCode)) { return; }
mod = true;
}
@@ -1665,7 +1665,7 @@ struct CalendarDataSink : public ResourceSink {
// Set the resources to visit on the next calendar
if (!resourcesToVisitNext.isNull()) {
- resourcesToVisit = std::move(resourcesToVisitNext);
+ resourcesToVisit = std::move(resourcesToVisitNext);
}
}
@@ -1690,12 +1690,12 @@ struct CalendarDataSink : public ResourceSink {
if (value.getType() == URES_STRING) {
// We are on a leaf, store the map elements into the stringMap
if (i == 0) {
- // mapRefs will keep ownership of 'stringMap':
- stringMap = mapRefs.create(FALSE, errorCode);
- if (stringMap == NULL) {
- errorCode = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
+ // mapRefs will keep ownership of 'stringMap':
+ stringMap = mapRefs.create(FALSE, errorCode);
+ if (stringMap == NULL) {
+ errorCode = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
maps.put(path, stringMap, errorCode);
if (U_FAILURE(errorCode)) { return; }
stringMap->setValueDeleter(uprv_deleteUObject);
@@ -2177,16 +2177,16 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError
// The ordering of the following statements is important.
if (fLeapMonthPatterns[kLeapMonthPatternFormatAbbrev].isEmpty()) {
fLeapMonthPatterns[kLeapMonthPatternFormatAbbrev].setTo(fLeapMonthPatterns[kLeapMonthPatternFormatWide]);
- }
+ }
if (fLeapMonthPatterns[kLeapMonthPatternFormatNarrow].isEmpty()) {
fLeapMonthPatterns[kLeapMonthPatternFormatNarrow].setTo(fLeapMonthPatterns[kLeapMonthPatternStandaloneNarrow]);
- }
+ }
if (fLeapMonthPatterns[kLeapMonthPatternStandaloneWide].isEmpty()) {
fLeapMonthPatterns[kLeapMonthPatternStandaloneWide].setTo(fLeapMonthPatterns[kLeapMonthPatternFormatWide]);
- }
+ }
if (fLeapMonthPatterns[kLeapMonthPatternStandaloneAbbrev].isEmpty()) {
fLeapMonthPatterns[kLeapMonthPatternStandaloneAbbrev].setTo(fLeapMonthPatterns[kLeapMonthPatternFormatAbbrev]);
- }
+ }
// end of hack
fLeapMonthPatternsCount = kMonthPatternsCount;
} else {
@@ -2221,8 +2221,8 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError
++typeMapPtr;
}
if (typeMapPtr->usageTypeName != NULL && compResult == 0) {
- fCapitalization[typeMapPtr->usageTypeEnumValue][0] = static_cast<UBool>(intVector[0]);
- fCapitalization[typeMapPtr->usageTypeEnumValue][1] = static_cast<UBool>(intVector[1]);
+ fCapitalization[typeMapPtr->usageTypeEnumValue][0] = static_cast<UBool>(intVector[0]);
+ fCapitalization[typeMapPtr->usageTypeEnumValue][1] = static_cast<UBool>(intVector[1]);
}
}
}
@@ -2338,21 +2338,21 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError
assignArray(fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, fShortMonths, fShortMonthsCount);
}
- // Load AM/PM markers; if wide or narrow not available, use short
- UErrorCode ampmStatus = U_ZERO_ERROR;
+ // Load AM/PM markers; if wide or narrow not available, use short
+ UErrorCode ampmStatus = U_ZERO_ERROR;
initField(&fAmPms, fAmPmsCount, calendarSink,
- buildResourcePath(path, gAmPmMarkersTag, ampmStatus), ampmStatus);
- if (U_FAILURE(ampmStatus)) {
- initField(&fAmPms, fAmPmsCount, calendarSink,
- buildResourcePath(path, gAmPmMarkersAbbrTag, status), status);
- }
- ampmStatus = U_ZERO_ERROR;
+ buildResourcePath(path, gAmPmMarkersTag, ampmStatus), ampmStatus);
+ if (U_FAILURE(ampmStatus)) {
+ initField(&fAmPms, fAmPmsCount, calendarSink,
+ buildResourcePath(path, gAmPmMarkersAbbrTag, status), status);
+ }
+ ampmStatus = U_ZERO_ERROR;
initField(&fNarrowAmPms, fNarrowAmPmsCount, calendarSink,
- buildResourcePath(path, gAmPmMarkersNarrowTag, ampmStatus), ampmStatus);
- if (U_FAILURE(ampmStatus)) {
- initField(&fNarrowAmPms, fNarrowAmPmsCount, calendarSink,
- buildResourcePath(path, gAmPmMarkersAbbrTag, status), status);
- }
+ buildResourcePath(path, gAmPmMarkersNarrowTag, ampmStatus), ampmStatus);
+ if (U_FAILURE(ampmStatus)) {
+ initField(&fNarrowAmPms, fNarrowAmPmsCount, calendarSink,
+ buildResourcePath(path, gAmPmMarkersAbbrTag, status), status);
+ }
// Load quarters
initField(&fQuarters, fQuartersCount, calendarSink,
diff --git a/contrib/libs/icu/i18n/dtitv_impl.h b/contrib/libs/icu/i18n/dtitv_impl.h
index c7addf37fb..5b66af065d 100644
--- a/contrib/libs/icu/i18n/dtitv_impl.h
+++ b/contrib/libs/icu/i18n/dtitv_impl.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -88,7 +88,7 @@
#define MAX_E_COUNT 5
#define MAX_M_COUNT 5
//#define MAX_INTERVAL_INDEX 4
-#define MAX_POSITIVE_INT 56632
+#define MAX_POSITIVE_INT 56632
#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/dtitvfmt.cpp b/contrib/libs/icu/i18n/dtitvfmt.cpp
index b71a571d1c..e4cef37f60 100644
--- a/contrib/libs/icu/i18n/dtitvfmt.cpp
+++ b/contrib/libs/icu/i18n/dtitvfmt.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*******************************************************************************
* Copyright (C) 2008-2016, International Business Machines Corporation and
@@ -28,7 +28,7 @@
#include "dtitv_impl.h"
#include "mutex.h"
#include "uresimp.h"
-#include "formattedval_impl.h"
+#include "formattedval_impl.h"
#ifdef DTITVFMT_DEBUG
#include <iostream>
@@ -66,23 +66,23 @@ static const UChar gLaterFirstPrefix[] = {LOW_L, LOW_A, LOW_T, LOW_E, LOW_S,LOW_
static const UChar gEarlierFirstPrefix[] = {LOW_E, LOW_A, LOW_R, LOW_L, LOW_I, LOW_E, LOW_S, LOW_T, CAP_F, LOW_I, LOW_R, LOW_S, LOW_T, COLON};
-class FormattedDateIntervalData : public FormattedValueFieldPositionIteratorImpl {
-public:
- FormattedDateIntervalData(UErrorCode& status) : FormattedValueFieldPositionIteratorImpl(5, status) {}
- virtual ~FormattedDateIntervalData();
-};
-
-FormattedDateIntervalData::~FormattedDateIntervalData() = default;
-
-UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(FormattedDateInterval)
-
-
+class FormattedDateIntervalData : public FormattedValueFieldPositionIteratorImpl {
+public:
+ FormattedDateIntervalData(UErrorCode& status) : FormattedValueFieldPositionIteratorImpl(5, status) {}
+ virtual ~FormattedDateIntervalData();
+};
+
+FormattedDateIntervalData::~FormattedDateIntervalData() = default;
+
+UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(FormattedDateInterval)
+
+
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateIntervalFormat)
// Mutex, protects access to fDateFormat, fFromCalendar and fToCalendar.
// Needed because these data members are modified by const methods of DateIntervalFormat.
-static UMutex gFormatterMutex;
+static UMutex gFormatterMutex;
DateIntervalFormat* U_EXPORT2
DateIntervalFormat::createInstance(const UnicodeString& skeleton,
@@ -108,10 +108,10 @@ DateIntervalFormat::createInstance(const UnicodeString& skeleton,
#endif
DateIntervalInfo* dtitvinf = new DateIntervalInfo(locale, status);
- if (dtitvinf == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
+ if (dtitvinf == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
return create(locale, dtitvinf, &skeleton, status);
}
@@ -136,27 +136,27 @@ DateIntervalFormat::createInstance(const UnicodeString& skeleton,
DateIntervalFormat::DateIntervalFormat()
-: fInfo(nullptr),
- fDateFormat(nullptr),
- fFromCalendar(nullptr),
- fToCalendar(nullptr),
+: fInfo(nullptr),
+ fDateFormat(nullptr),
+ fFromCalendar(nullptr),
+ fToCalendar(nullptr),
fLocale(Locale::getRoot()),
- fDatePattern(nullptr),
- fTimePattern(nullptr),
- fDateTimeFormat(nullptr)
+ fDatePattern(nullptr),
+ fTimePattern(nullptr),
+ fDateTimeFormat(nullptr)
{}
DateIntervalFormat::DateIntervalFormat(const DateIntervalFormat& itvfmt)
: Format(itvfmt),
- fInfo(nullptr),
- fDateFormat(nullptr),
- fFromCalendar(nullptr),
- fToCalendar(nullptr),
+ fInfo(nullptr),
+ fDateFormat(nullptr),
+ fFromCalendar(nullptr),
+ fToCalendar(nullptr),
fLocale(itvfmt.fLocale),
- fDatePattern(nullptr),
- fTimePattern(nullptr),
- fDateTimeFormat(nullptr) {
+ fDatePattern(nullptr),
+ fTimePattern(nullptr),
+ fDateTimeFormat(nullptr) {
*this = itvfmt;
}
@@ -174,25 +174,25 @@ DateIntervalFormat::operator=(const DateIntervalFormat& itvfmt) {
{
Mutex lock(&gFormatterMutex);
if ( itvfmt.fDateFormat ) {
- fDateFormat = itvfmt.fDateFormat->clone();
+ fDateFormat = itvfmt.fDateFormat->clone();
} else {
- fDateFormat = nullptr;
+ fDateFormat = nullptr;
}
if ( itvfmt.fFromCalendar ) {
fFromCalendar = itvfmt.fFromCalendar->clone();
} else {
- fFromCalendar = nullptr;
+ fFromCalendar = nullptr;
}
if ( itvfmt.fToCalendar ) {
fToCalendar = itvfmt.fToCalendar->clone();
} else {
- fToCalendar = nullptr;
+ fToCalendar = nullptr;
}
}
if ( itvfmt.fInfo ) {
fInfo = itvfmt.fInfo->clone();
} else {
- fInfo = nullptr;
+ fInfo = nullptr;
}
fSkeleton = itvfmt.fSkeleton;
int8_t i;
@@ -200,9 +200,9 @@ DateIntervalFormat::operator=(const DateIntervalFormat& itvfmt) {
fIntervalPatterns[i] = itvfmt.fIntervalPatterns[i];
}
fLocale = itvfmt.fLocale;
- fDatePattern = (itvfmt.fDatePattern)? itvfmt.fDatePattern->clone(): nullptr;
- fTimePattern = (itvfmt.fTimePattern)? itvfmt.fTimePattern->clone(): nullptr;
- fDateTimeFormat = (itvfmt.fDateTimeFormat)? itvfmt.fDateTimeFormat->clone(): nullptr;
+ fDatePattern = (itvfmt.fDatePattern)? itvfmt.fDatePattern->clone(): nullptr;
+ fTimePattern = (itvfmt.fTimePattern)? itvfmt.fTimePattern->clone(): nullptr;
+ fDateTimeFormat = (itvfmt.fDateTimeFormat)? itvfmt.fDateTimeFormat->clone(): nullptr;
}
return *this;
}
@@ -219,8 +219,8 @@ DateIntervalFormat::~DateIntervalFormat() {
}
-DateIntervalFormat*
-DateIntervalFormat::clone() const {
+DateIntervalFormat*
+DateIntervalFormat::clone() const {
return new DateIntervalFormat(*this);
}
@@ -231,21 +231,21 @@ DateIntervalFormat::operator==(const Format& other) const {
const DateIntervalFormat* fmt = (DateIntervalFormat*)&other;
if (this == fmt) {return TRUE;}
if (!Format::operator==(other)) {return FALSE;}
- if ((fInfo != fmt->fInfo) && (fInfo == nullptr || fmt->fInfo == nullptr)) {return FALSE;}
+ if ((fInfo != fmt->fInfo) && (fInfo == nullptr || fmt->fInfo == nullptr)) {return FALSE;}
if (fInfo && fmt->fInfo && (*fInfo != *fmt->fInfo )) {return FALSE;}
{
Mutex lock(&gFormatterMutex);
- if (fDateFormat != fmt->fDateFormat && (fDateFormat == nullptr || fmt->fDateFormat == nullptr)) {return FALSE;}
+ if (fDateFormat != fmt->fDateFormat && (fDateFormat == nullptr || fmt->fDateFormat == nullptr)) {return FALSE;}
if (fDateFormat && fmt->fDateFormat && (*fDateFormat != *fmt->fDateFormat)) {return FALSE;}
}
// note: fFromCalendar and fToCalendar hold no persistent state, and therefore do not participate in operator ==.
// fDateFormat has the master calendar for the DateIntervalFormat.
if (fSkeleton != fmt->fSkeleton) {return FALSE;}
- if (fDatePattern != fmt->fDatePattern && (fDatePattern == nullptr || fmt->fDatePattern == nullptr)) {return FALSE;}
+ if (fDatePattern != fmt->fDatePattern && (fDatePattern == nullptr || fmt->fDatePattern == nullptr)) {return FALSE;}
if (fDatePattern && fmt->fDatePattern && (*fDatePattern != *fmt->fDatePattern)) {return FALSE;}
- if (fTimePattern != fmt->fTimePattern && (fTimePattern == nullptr || fmt->fTimePattern == nullptr)) {return FALSE;}
+ if (fTimePattern != fmt->fTimePattern && (fTimePattern == nullptr || fmt->fTimePattern == nullptr)) {return FALSE;}
if (fTimePattern && fmt->fTimePattern && (*fTimePattern != *fmt->fTimePattern)) {return FALSE;}
- if (fDateTimeFormat != fmt->fDateTimeFormat && (fDateTimeFormat == nullptr || fmt->fDateTimeFormat == nullptr)) {return FALSE;}
+ if (fDateTimeFormat != fmt->fDateTimeFormat && (fDateTimeFormat == nullptr || fmt->fDateTimeFormat == nullptr)) {return FALSE;}
if (fDateTimeFormat && fmt->fDateTimeFormat && (*fDateTimeFormat != *fmt->fDateTimeFormat)) {return FALSE;}
if (fLocale != fmt->fLocale) {return FALSE;}
@@ -270,7 +270,7 @@ DateIntervalFormat::format(const Formattable& obj,
if ( obj.getType() == Formattable::kObject ) {
const UObject* formatObj = obj.getObject();
const DateInterval* interval = dynamic_cast<const DateInterval*>(formatObj);
- if (interval != nullptr) {
+ if (interval != nullptr) {
return format(interval, appendTo, fieldPosition, status);
}
}
@@ -287,142 +287,142 @@ DateIntervalFormat::format(const DateInterval* dtInterval,
if ( U_FAILURE(status) ) {
return appendTo;
}
- if (fDateFormat == nullptr || fInfo == nullptr) {
+ if (fDateFormat == nullptr || fInfo == nullptr) {
status = U_INVALID_STATE_ERROR;
return appendTo;
}
- FieldPositionOnlyHandler handler(fieldPosition);
- handler.setAcceptFirstOnly(TRUE);
- int8_t ignore;
-
+ FieldPositionOnlyHandler handler(fieldPosition);
+ handler.setAcceptFirstOnly(TRUE);
+ int8_t ignore;
+
Mutex lock(&gFormatterMutex);
- return formatIntervalImpl(*dtInterval, appendTo, ignore, handler, status);
-}
-
-
-FormattedDateInterval DateIntervalFormat::formatToValue(
- const DateInterval& dtInterval,
- UErrorCode& status) const {
- if (U_FAILURE(status)) {
- return FormattedDateInterval(status);
- }
- // LocalPointer only sets OOM status if U_SUCCESS is true.
- LocalPointer<FormattedDateIntervalData> result(new FormattedDateIntervalData(status), status);
- if (U_FAILURE(status)) {
- return FormattedDateInterval(status);
- }
- UnicodeString string;
- int8_t firstIndex;
- auto handler = result->getHandler(status);
- handler.setCategory(UFIELD_CATEGORY_DATE);
- {
- Mutex lock(&gFormatterMutex);
- formatIntervalImpl(dtInterval, string, firstIndex, handler, status);
- }
- handler.getError(status);
- result->appendString(string, status);
- if (U_FAILURE(status)) {
- return FormattedDateInterval(status);
- }
-
- // Compute the span fields and sort them into place:
- if (firstIndex != -1) {
- result->addOverlapSpans(UFIELD_CATEGORY_DATE_INTERVAL_SPAN, firstIndex, status);
- if (U_FAILURE(status)) {
- return FormattedDateInterval(status);
- }
- result->sort();
- }
-
- return FormattedDateInterval(result.orphan());
+ return formatIntervalImpl(*dtInterval, appendTo, ignore, handler, status);
}
+FormattedDateInterval DateIntervalFormat::formatToValue(
+ const DateInterval& dtInterval,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return FormattedDateInterval(status);
+ }
+ // LocalPointer only sets OOM status if U_SUCCESS is true.
+ LocalPointer<FormattedDateIntervalData> result(new FormattedDateIntervalData(status), status);
+ if (U_FAILURE(status)) {
+ return FormattedDateInterval(status);
+ }
+ UnicodeString string;
+ int8_t firstIndex;
+ auto handler = result->getHandler(status);
+ handler.setCategory(UFIELD_CATEGORY_DATE);
+ {
+ Mutex lock(&gFormatterMutex);
+ formatIntervalImpl(dtInterval, string, firstIndex, handler, status);
+ }
+ handler.getError(status);
+ result->appendString(string, status);
+ if (U_FAILURE(status)) {
+ return FormattedDateInterval(status);
+ }
+
+ // Compute the span fields and sort them into place:
+ if (firstIndex != -1) {
+ result->addOverlapSpans(UFIELD_CATEGORY_DATE_INTERVAL_SPAN, firstIndex, status);
+ if (U_FAILURE(status)) {
+ return FormattedDateInterval(status);
+ }
+ result->sort();
+ }
+
+ return FormattedDateInterval(result.orphan());
+}
+
+
UnicodeString&
DateIntervalFormat::format(Calendar& fromCalendar,
Calendar& toCalendar,
UnicodeString& appendTo,
FieldPosition& pos,
UErrorCode& status) const {
- FieldPositionOnlyHandler handler(pos);
- handler.setAcceptFirstOnly(TRUE);
- int8_t ignore;
-
+ FieldPositionOnlyHandler handler(pos);
+ handler.setAcceptFirstOnly(TRUE);
+ int8_t ignore;
+
Mutex lock(&gFormatterMutex);
- return formatImpl(fromCalendar, toCalendar, appendTo, ignore, handler, status);
-}
-
-
-FormattedDateInterval DateIntervalFormat::formatToValue(
- Calendar& fromCalendar,
- Calendar& toCalendar,
- UErrorCode& status) const {
- if (U_FAILURE(status)) {
- return FormattedDateInterval(status);
- }
- // LocalPointer only sets OOM status if U_SUCCESS is true.
- LocalPointer<FormattedDateIntervalData> result(new FormattedDateIntervalData(status), status);
- if (U_FAILURE(status)) {
- return FormattedDateInterval(status);
- }
- UnicodeString string;
- int8_t firstIndex;
- auto handler = result->getHandler(status);
- handler.setCategory(UFIELD_CATEGORY_DATE);
- {
- Mutex lock(&gFormatterMutex);
- formatImpl(fromCalendar, toCalendar, string, firstIndex, handler, status);
- }
- handler.getError(status);
- result->appendString(string, status);
- if (U_FAILURE(status)) {
- return FormattedDateInterval(status);
- }
-
- // Compute the span fields and sort them into place:
- if (firstIndex != -1) {
- result->addOverlapSpans(UFIELD_CATEGORY_DATE_INTERVAL_SPAN, firstIndex, status);
- result->sort();
- }
-
- return FormattedDateInterval(result.orphan());
-}
-
-
-UnicodeString& DateIntervalFormat::formatIntervalImpl(
- const DateInterval& dtInterval,
- UnicodeString& appendTo,
- int8_t& firstIndex,
- FieldPositionHandler& fphandler,
- UErrorCode& status) const {
- if (U_FAILURE(status)) {
- return appendTo;
- }
- if (fFromCalendar == nullptr || fToCalendar == nullptr) {
- status = U_INVALID_STATE_ERROR;
- return appendTo;
- }
- fFromCalendar->setTime(dtInterval.getFromDate(), status);
- fToCalendar->setTime(dtInterval.getToDate(), status);
- return formatImpl(*fFromCalendar, *fToCalendar, appendTo, firstIndex, fphandler, status);
+ return formatImpl(fromCalendar, toCalendar, appendTo, ignore, handler, status);
}
+FormattedDateInterval DateIntervalFormat::formatToValue(
+ Calendar& fromCalendar,
+ Calendar& toCalendar,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return FormattedDateInterval(status);
+ }
+ // LocalPointer only sets OOM status if U_SUCCESS is true.
+ LocalPointer<FormattedDateIntervalData> result(new FormattedDateIntervalData(status), status);
+ if (U_FAILURE(status)) {
+ return FormattedDateInterval(status);
+ }
+ UnicodeString string;
+ int8_t firstIndex;
+ auto handler = result->getHandler(status);
+ handler.setCategory(UFIELD_CATEGORY_DATE);
+ {
+ Mutex lock(&gFormatterMutex);
+ formatImpl(fromCalendar, toCalendar, string, firstIndex, handler, status);
+ }
+ handler.getError(status);
+ result->appendString(string, status);
+ if (U_FAILURE(status)) {
+ return FormattedDateInterval(status);
+ }
+
+ // Compute the span fields and sort them into place:
+ if (firstIndex != -1) {
+ result->addOverlapSpans(UFIELD_CATEGORY_DATE_INTERVAL_SPAN, firstIndex, status);
+ result->sort();
+ }
+
+ return FormattedDateInterval(result.orphan());
+}
+
+
+UnicodeString& DateIntervalFormat::formatIntervalImpl(
+ const DateInterval& dtInterval,
+ UnicodeString& appendTo,
+ int8_t& firstIndex,
+ FieldPositionHandler& fphandler,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return appendTo;
+ }
+ if (fFromCalendar == nullptr || fToCalendar == nullptr) {
+ status = U_INVALID_STATE_ERROR;
+ return appendTo;
+ }
+ fFromCalendar->setTime(dtInterval.getFromDate(), status);
+ fToCalendar->setTime(dtInterval.getToDate(), status);
+ return formatImpl(*fFromCalendar, *fToCalendar, appendTo, firstIndex, fphandler, status);
+}
+
+
UnicodeString&
DateIntervalFormat::formatImpl(Calendar& fromCalendar,
Calendar& toCalendar,
UnicodeString& appendTo,
- int8_t& firstIndex,
- FieldPositionHandler& fphandler,
+ int8_t& firstIndex,
+ FieldPositionHandler& fphandler,
UErrorCode& status) const {
if ( U_FAILURE(status) ) {
return appendTo;
}
- // Initialize firstIndex to -1 (single date, no range)
- firstIndex = -1;
-
+ // Initialize firstIndex to -1 (single date, no range)
+ firstIndex = -1;
+
// not support different calendar types and time zones
//if ( fromCalendar.getType() != toCalendar.getType() ) {
if ( !fromCalendar.isEquivalentTo(toCalendar) ) {
@@ -456,9 +456,9 @@ DateIntervalFormat::formatImpl(Calendar& fromCalendar,
} else if ( fromCalendar.get(UCAL_SECOND, status) !=
toCalendar.get(UCAL_SECOND, status) ) {
field = UCAL_SECOND;
- } else if ( fromCalendar.get(UCAL_MILLISECOND, status) !=
- toCalendar.get(UCAL_MILLISECOND, status) ) {
- field = UCAL_MILLISECOND;
+ } else if ( fromCalendar.get(UCAL_MILLISECOND, status) !=
+ toCalendar.get(UCAL_MILLISECOND, status) ) {
+ field = UCAL_MILLISECOND;
}
if ( U_FAILURE(status) ) {
@@ -468,9 +468,9 @@ DateIntervalFormat::formatImpl(Calendar& fromCalendar,
/* ignore the millisecond etc. small fields' difference.
* use single date when all the above are the same.
*/
- return fDateFormat->_format(fromCalendar, appendTo, fphandler, status);
+ return fDateFormat->_format(fromCalendar, appendTo, fphandler, status);
}
- UBool fromToOnSameDay = (field==UCAL_AM_PM || field==UCAL_HOUR || field==UCAL_MINUTE || field==UCAL_SECOND || field==UCAL_MILLISECOND);
+ UBool fromToOnSameDay = (field==UCAL_AM_PM || field==UCAL_HOUR || field==UCAL_MINUTE || field==UCAL_SECOND || field==UCAL_MILLISECOND);
// following call should not set wrong status,
// all the pass-in fields are valid till here
@@ -485,9 +485,9 @@ DateIntervalFormat::formatImpl(Calendar& fromCalendar,
* the smallest calendar field in pattern,
* return single date format.
*/
- return fDateFormat->_format(fromCalendar, appendTo, fphandler, status);
+ return fDateFormat->_format(fromCalendar, appendTo, fphandler, status);
}
- return fallbackFormat(fromCalendar, toCalendar, fromToOnSameDay, appendTo, firstIndex, fphandler, status);
+ return fallbackFormat(fromCalendar, toCalendar, fromToOnSameDay, appendTo, firstIndex, fphandler, status);
}
// If the first part in interval pattern is empty,
// the 2nd part of it saves the full-pattern used in fall-back.
@@ -497,7 +497,7 @@ DateIntervalFormat::formatImpl(Calendar& fromCalendar,
UnicodeString originalPattern;
fDateFormat->toPattern(originalPattern);
fDateFormat->applyPattern(intervalPattern.secondPart);
- appendTo = fallbackFormat(fromCalendar, toCalendar, fromToOnSameDay, appendTo, firstIndex, fphandler, status);
+ appendTo = fallbackFormat(fromCalendar, toCalendar, fromToOnSameDay, appendTo, firstIndex, fphandler, status);
fDateFormat->applyPattern(originalPattern);
return appendTo;
}
@@ -506,22 +506,22 @@ DateIntervalFormat::formatImpl(Calendar& fromCalendar,
if ( intervalPattern.laterDateFirst ) {
firstCal = &toCalendar;
secondCal = &fromCalendar;
- firstIndex = 1;
+ firstIndex = 1;
} else {
firstCal = &fromCalendar;
secondCal = &toCalendar;
- firstIndex = 0;
+ firstIndex = 0;
}
// break the interval pattern into 2 parts,
// first part should not be empty,
UnicodeString originalPattern;
fDateFormat->toPattern(originalPattern);
fDateFormat->applyPattern(intervalPattern.firstPart);
- fDateFormat->_format(*firstCal, appendTo, fphandler, status);
-
+ fDateFormat->_format(*firstCal, appendTo, fphandler, status);
+
if ( !intervalPattern.secondPart.isEmpty() ) {
fDateFormat->applyPattern(intervalPattern.secondPart);
- fDateFormat->_format(*secondCal, appendTo, fphandler, status);
+ fDateFormat->_format(*secondCal, appendTo, fphandler, status);
}
fDateFormat->applyPattern(originalPattern);
return appendTo;
@@ -552,17 +552,17 @@ DateIntervalFormat::setDateIntervalInfo(const DateIntervalInfo& newItvPattern,
UErrorCode& status) {
delete fInfo;
fInfo = new DateIntervalInfo(newItvPattern);
- if (fInfo == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
+ if (fInfo == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
// Delete patterns that get reset by initializePattern
delete fDatePattern;
- fDatePattern = nullptr;
+ fDatePattern = nullptr;
delete fTimePattern;
- fTimePattern = nullptr;
+ fTimePattern = nullptr;
delete fDateTimeFormat;
- fDateTimeFormat = nullptr;
+ fDateTimeFormat = nullptr;
if (fDateFormat) {
initializePattern(status);
@@ -580,7 +580,7 @@ DateIntervalFormat::getDateFormat() const {
void
DateIntervalFormat::adoptTimeZone(TimeZone* zone)
{
- if (fDateFormat != nullptr) {
+ if (fDateFormat != nullptr) {
fDateFormat->adoptTimeZone(zone);
}
// The fDateFormat has the master calendar for the DateIntervalFormat and has
@@ -598,7 +598,7 @@ DateIntervalFormat::adoptTimeZone(TimeZone* zone)
void
DateIntervalFormat::setTimeZone(const TimeZone& zone)
{
- if (fDateFormat != nullptr) {
+ if (fDateFormat != nullptr) {
fDateFormat->setTimeZone(zone);
}
// The fDateFormat has the master calendar for the DateIntervalFormat;
@@ -614,11 +614,11 @@ DateIntervalFormat::setTimeZone(const TimeZone& zone)
const TimeZone&
DateIntervalFormat::getTimeZone() const
{
- if (fDateFormat != nullptr) {
+ if (fDateFormat != nullptr) {
Mutex lock(&gFormatterMutex);
return fDateFormat->getTimeZone();
}
- // If fDateFormat is nullptr (unexpected), create default timezone.
+ // If fDateFormat is nullptr (unexpected), create default timezone.
return *(TimeZone::createDefault());
}
@@ -626,14 +626,14 @@ DateIntervalFormat::DateIntervalFormat(const Locale& locale,
DateIntervalInfo* dtItvInfo,
const UnicodeString* skeleton,
UErrorCode& status)
-: fInfo(nullptr),
- fDateFormat(nullptr),
- fFromCalendar(nullptr),
- fToCalendar(nullptr),
+: fInfo(nullptr),
+ fDateFormat(nullptr),
+ fFromCalendar(nullptr),
+ fToCalendar(nullptr),
fLocale(locale),
- fDatePattern(nullptr),
- fTimePattern(nullptr),
- fDateTimeFormat(nullptr)
+ fDatePattern(nullptr),
+ fTimePattern(nullptr),
+ fDateTimeFormat(nullptr)
{
LocalPointer<DateIntervalInfo> info(dtItvInfo, status);
LocalPointer<SimpleDateFormat> dtfmt(static_cast<SimpleDateFormat *>(
@@ -661,7 +661,7 @@ DateIntervalFormat::create(const Locale& locale,
UErrorCode& status) {
DateIntervalFormat* f = new DateIntervalFormat(locale, dtitvinf,
skeleton, status);
- if ( f == nullptr ) {
+ if ( f == nullptr ) {
status = U_MEMORY_ALLOCATION_ERROR;
delete dtitvinf;
} else if ( U_FAILURE(status) ) {
@@ -778,7 +778,7 @@ DateIntervalFormat::initializePattern(UErrorCode& status) {
// with the time interval.
// The date/time pattern ( such as {0} {1} ) is saved in
// calendar, that is why need to get the CalendarData here.
- LocalUResourceBundlePointer dateTimePatternsRes(ures_open(nullptr, locale.getBaseName(), &status));
+ LocalUResourceBundlePointer dateTimePatternsRes(ures_open(nullptr, locale.getBaseName(), &status));
ures_getByKey(dateTimePatternsRes.getAlias(), gCalendarTag,
dateTimePatternsRes.getAlias(), &status);
ures_getByKeyWithFallback(dateTimePatternsRes.getAlias(), gGregorianTag,
@@ -793,10 +793,10 @@ DateIntervalFormat::initializePattern(UErrorCode& status) {
&dateTimeFormatLength, &status);
if ( U_SUCCESS(status) && dateTimeFormatLength >= 3 ) {
fDateTimeFormat = new UnicodeString(dateTimeFormat, dateTimeFormatLength);
- if (fDateTimeFormat == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
+ if (fDateTimeFormat == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
}
}
@@ -820,9 +820,9 @@ DateIntervalFormat::initializePattern(UErrorCode& status) {
// the first part of the pattern is empty,
// the second part of the pattern is the full-pattern
// should be used in fall-back.
- setPatternInfo(UCAL_DATE, nullptr, &pattern, fInfo->getDefaultOrder());
- setPatternInfo(UCAL_MONTH, nullptr, &pattern, fInfo->getDefaultOrder());
- setPatternInfo(UCAL_YEAR, nullptr, &pattern, fInfo->getDefaultOrder());
+ setPatternInfo(UCAL_DATE, nullptr, &pattern, fInfo->getDefaultOrder());
+ setPatternInfo(UCAL_MONTH, nullptr, &pattern, fInfo->getDefaultOrder());
+ setPatternInfo(UCAL_YEAR, nullptr, &pattern, fInfo->getDefaultOrder());
} else {
// TODO: fall back
}
@@ -846,9 +846,9 @@ DateIntervalFormat::initializePattern(UErrorCode& status) {
// the first part of the pattern is empty,
// the second part of the pattern is the full-pattern
// should be used in fall-back.
- setPatternInfo(UCAL_DATE, nullptr, &pattern, fInfo->getDefaultOrder());
- setPatternInfo(UCAL_MONTH, nullptr, &pattern, fInfo->getDefaultOrder());
- setPatternInfo(UCAL_YEAR, nullptr, &pattern, fInfo->getDefaultOrder());
+ setPatternInfo(UCAL_DATE, nullptr, &pattern, fInfo->getDefaultOrder());
+ setPatternInfo(UCAL_MONTH, nullptr, &pattern, fInfo->getDefaultOrder());
+ setPatternInfo(UCAL_YEAR, nullptr, &pattern, fInfo->getDefaultOrder());
} else {
/* if both present,
* 1) when the year, month, or day differs,
@@ -883,7 +883,7 @@ DateIntervalFormat::initializePattern(UErrorCode& status) {
* range expression for the time.
*/
- if ( fDateTimeFormat == nullptr ) {
+ if ( fDateTimeFormat == nullptr ) {
// earlier failure getting dateTimeFormat
return;
}
@@ -1004,7 +1004,7 @@ DateIntervalFormat::getDateTimeSkeleton(const UnicodeString& skeleton,
if ( MCount < 3 ) {
normalizedDateSkeleton.append(CAP_M);
} else {
- for ( int32_t j = 0; j < MCount && j < MAX_M_COUNT; ++j) {
+ for ( int32_t j = 0; j < MCount && j < MAX_M_COUNT; ++j) {
normalizedDateSkeleton.append(CAP_M);
}
}
@@ -1013,7 +1013,7 @@ DateIntervalFormat::getDateTimeSkeleton(const UnicodeString& skeleton,
if ( ECount <= 3 ) {
normalizedDateSkeleton.append(CAP_E);
} else {
- for ( int32_t j = 0; j < ECount && j < MAX_E_COUNT; ++j ) {
+ for ( int32_t j = 0; j < ECount && j < MAX_E_COUNT; ++j ) {
normalizedDateSkeleton.append(CAP_E);
}
}
@@ -1093,16 +1093,16 @@ DateIntervalFormat::setSeparateDateTimePtn(
int8_t differenceInfo = 0;
const UnicodeString* bestSkeleton = fInfo->getBestSkeleton(*skeleton,
differenceInfo);
- /* best skeleton could be nullptr.
+ /* best skeleton could be nullptr.
For example: in "ca" resource file,
interval format is defined as following
intervalFormats{
fallback{"{0} - {1}"}
}
there is no skeletons/interval patterns defined,
- and the best skeleton match could be nullptr
+ and the best skeleton match could be nullptr
*/
- if ( bestSkeleton == nullptr ) {
+ if ( bestSkeleton == nullptr ) {
return false;
}
@@ -1113,13 +1113,13 @@ DateIntervalFormat::setSeparateDateTimePtn(
status = U_ZERO_ERROR;
fDatePattern = new UnicodeString(DateFormat::getBestPattern(
fLocale, dateSkeleton, status));
- // no way to report OOM. :(
+ // no way to report OOM. :(
}
if ( timeSkeleton.length() != 0) {
status = U_ZERO_ERROR;
fTimePattern = new UnicodeString(DateFormat::getBestPattern(
fLocale, timeSkeleton, status));
- // no way to report OOM. :(
+ // no way to report OOM. :(
}
// difference:
@@ -1151,9 +1151,9 @@ DateIntervalFormat::setSeparateDateTimePtn(
}
setIntervalPattern(UCAL_YEAR, skeleton, bestSkeleton, differenceInfo,
&extendedSkeleton, &extendedBestSkeleton);
- setIntervalPattern(UCAL_ERA, skeleton, bestSkeleton, differenceInfo,
- &extendedSkeleton, &extendedBestSkeleton);
- } else {
+ setIntervalPattern(UCAL_ERA, skeleton, bestSkeleton, differenceInfo,
+ &extendedSkeleton, &extendedBestSkeleton);
+ } else {
setIntervalPattern(UCAL_MINUTE, skeleton, bestSkeleton, differenceInfo);
setIntervalPattern(UCAL_HOUR, skeleton, bestSkeleton, differenceInfo);
setIntervalPattern(UCAL_AM_PM, skeleton, bestSkeleton, differenceInfo);
@@ -1175,7 +1175,7 @@ DateIntervalFormat::setFallbackPattern(UCalendarDateFields field,
if ( U_FAILURE(status) ) {
return;
}
- setPatternInfo(field, nullptr, &pattern, fInfo->getDefaultOrder());
+ setPatternInfo(field, nullptr, &pattern, fInfo->getDefaultOrder());
}
@@ -1425,37 +1425,37 @@ DateIntervalFormat::splitPatternInto2Part(const UnicodeString& intervalPattern)
return (i - count);
}
-void DateIntervalFormat::fallbackFormatRange(
- Calendar& fromCalendar,
- Calendar& toCalendar,
- UnicodeString& appendTo,
- int8_t& firstIndex,
- FieldPositionHandler& fphandler,
- UErrorCode& status) const {
- UnicodeString fallbackPattern;
- fInfo->getFallbackIntervalPattern(fallbackPattern);
- SimpleFormatter sf(fallbackPattern, 2, 2, status);
- if (U_FAILURE(status)) {
+void DateIntervalFormat::fallbackFormatRange(
+ Calendar& fromCalendar,
+ Calendar& toCalendar,
+ UnicodeString& appendTo,
+ int8_t& firstIndex,
+ FieldPositionHandler& fphandler,
+ UErrorCode& status) const {
+ UnicodeString fallbackPattern;
+ fInfo->getFallbackIntervalPattern(fallbackPattern);
+ SimpleFormatter sf(fallbackPattern, 2, 2, status);
+ if (U_FAILURE(status)) {
return;
}
- int32_t offsets[2];
- UnicodeString patternBody = sf.getTextWithNoArguments(offsets, 2);
-
- // TODO(ICU-20406): Use SimpleFormatter Iterator interface when available.
- if (offsets[0] < offsets[1]) {
- firstIndex = 0;
- appendTo.append(patternBody.tempSubStringBetween(0, offsets[0]));
- fDateFormat->_format(fromCalendar, appendTo, fphandler, status);
- appendTo.append(patternBody.tempSubStringBetween(offsets[0], offsets[1]));
- fDateFormat->_format(toCalendar, appendTo, fphandler, status);
- appendTo.append(patternBody.tempSubStringBetween(offsets[1]));
+ int32_t offsets[2];
+ UnicodeString patternBody = sf.getTextWithNoArguments(offsets, 2);
+
+ // TODO(ICU-20406): Use SimpleFormatter Iterator interface when available.
+ if (offsets[0] < offsets[1]) {
+ firstIndex = 0;
+ appendTo.append(patternBody.tempSubStringBetween(0, offsets[0]));
+ fDateFormat->_format(fromCalendar, appendTo, fphandler, status);
+ appendTo.append(patternBody.tempSubStringBetween(offsets[0], offsets[1]));
+ fDateFormat->_format(toCalendar, appendTo, fphandler, status);
+ appendTo.append(patternBody.tempSubStringBetween(offsets[1]));
} else {
- firstIndex = 1;
- appendTo.append(patternBody.tempSubStringBetween(0, offsets[1]));
- fDateFormat->_format(toCalendar, appendTo, fphandler, status);
- appendTo.append(patternBody.tempSubStringBetween(offsets[1], offsets[0]));
- fDateFormat->_format(fromCalendar, appendTo, fphandler, status);
- appendTo.append(patternBody.tempSubStringBetween(offsets[0]));
+ firstIndex = 1;
+ appendTo.append(patternBody.tempSubStringBetween(0, offsets[1]));
+ fDateFormat->_format(toCalendar, appendTo, fphandler, status);
+ appendTo.append(patternBody.tempSubStringBetween(offsets[1], offsets[0]));
+ fDateFormat->_format(fromCalendar, appendTo, fphandler, status);
+ appendTo.append(patternBody.tempSubStringBetween(offsets[0]));
}
}
@@ -1464,50 +1464,50 @@ DateIntervalFormat::fallbackFormat(Calendar& fromCalendar,
Calendar& toCalendar,
UBool fromToOnSameDay, // new
UnicodeString& appendTo,
- int8_t& firstIndex,
- FieldPositionHandler& fphandler,
+ int8_t& firstIndex,
+ FieldPositionHandler& fphandler,
UErrorCode& status) const {
if ( U_FAILURE(status) ) {
return appendTo;
}
-
+
UBool formatDatePlusTimeRange = (fromToOnSameDay && fDatePattern && fTimePattern);
if (formatDatePlusTimeRange) {
- SimpleFormatter sf(*fDateTimeFormat, 2, 2, status);
- if (U_FAILURE(status)) {
- return appendTo;
- }
- int32_t offsets[2];
- UnicodeString patternBody = sf.getTextWithNoArguments(offsets, 2);
-
- UnicodeString fullPattern; // for saving the pattern in fDateFormat
+ SimpleFormatter sf(*fDateTimeFormat, 2, 2, status);
+ if (U_FAILURE(status)) {
+ return appendTo;
+ }
+ int32_t offsets[2];
+ UnicodeString patternBody = sf.getTextWithNoArguments(offsets, 2);
+
+ UnicodeString fullPattern; // for saving the pattern in fDateFormat
fDateFormat->toPattern(fullPattern); // save current pattern, restore later
-
- // {0} is time range
- // {1} is single date portion
- // TODO(ICU-20406): Use SimpleFormatter Iterator interface when available.
- if (offsets[0] < offsets[1]) {
- appendTo.append(patternBody.tempSubStringBetween(0, offsets[0]));
- fDateFormat->applyPattern(*fTimePattern);
- fallbackFormatRange(fromCalendar, toCalendar, appendTo, firstIndex, fphandler, status);
- appendTo.append(patternBody.tempSubStringBetween(offsets[0], offsets[1]));
- fDateFormat->applyPattern(*fDatePattern);
- fDateFormat->_format(fromCalendar, appendTo, fphandler, status);
- appendTo.append(patternBody.tempSubStringBetween(offsets[1]));
- } else {
- appendTo.append(patternBody.tempSubStringBetween(0, offsets[1]));
- fDateFormat->applyPattern(*fDatePattern);
- fDateFormat->_format(fromCalendar, appendTo, fphandler, status);
- appendTo.append(patternBody.tempSubStringBetween(offsets[1], offsets[0]));
- fDateFormat->applyPattern(*fTimePattern);
- fallbackFormatRange(fromCalendar, toCalendar, appendTo, firstIndex, fphandler, status);
- appendTo.append(patternBody.tempSubStringBetween(offsets[0]));
- }
-
+
+ // {0} is time range
+ // {1} is single date portion
+ // TODO(ICU-20406): Use SimpleFormatter Iterator interface when available.
+ if (offsets[0] < offsets[1]) {
+ appendTo.append(patternBody.tempSubStringBetween(0, offsets[0]));
+ fDateFormat->applyPattern(*fTimePattern);
+ fallbackFormatRange(fromCalendar, toCalendar, appendTo, firstIndex, fphandler, status);
+ appendTo.append(patternBody.tempSubStringBetween(offsets[0], offsets[1]));
+ fDateFormat->applyPattern(*fDatePattern);
+ fDateFormat->_format(fromCalendar, appendTo, fphandler, status);
+ appendTo.append(patternBody.tempSubStringBetween(offsets[1]));
+ } else {
+ appendTo.append(patternBody.tempSubStringBetween(0, offsets[1]));
+ fDateFormat->applyPattern(*fDatePattern);
+ fDateFormat->_format(fromCalendar, appendTo, fphandler, status);
+ appendTo.append(patternBody.tempSubStringBetween(offsets[1], offsets[0]));
+ fDateFormat->applyPattern(*fTimePattern);
+ fallbackFormatRange(fromCalendar, toCalendar, appendTo, firstIndex, fphandler, status);
+ appendTo.append(patternBody.tempSubStringBetween(offsets[0]));
+ }
+
// restore full pattern
fDateFormat->applyPattern(fullPattern);
- } else {
- fallbackFormatRange(fromCalendar, toCalendar, appendTo, firstIndex, fphandler, status);
+ } else {
+ fallbackFormatRange(fromCalendar, toCalendar, appendTo, firstIndex, fphandler, status);
}
return appendTo;
}
@@ -1679,7 +1679,7 @@ DateIntervalFormat::fgCalendarFieldToPatternLetter[] =
};
-
+
U_NAMESPACE_END
#endif
diff --git a/contrib/libs/icu/i18n/dtitvinf.cpp b/contrib/libs/icu/i18n/dtitvinf.cpp
index 25536346ec..127240a6e6 100644
--- a/contrib/libs/icu/i18n/dtitvinf.cpp
+++ b/contrib/libs/icu/i18n/dtitvinf.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*******************************************************************************
* Copyright (C) 2008-2016, International Business Machines Corporation and
@@ -42,15 +42,15 @@ U_NAMESPACE_BEGIN
#ifdef DTITVINF_DEBUG
-#define PRINTMESG(msg) UPRV_BLOCK_MACRO_BEGIN { \
- std::cout << "(" << __FILE__ << ":" << __LINE__ << ") " << msg << "\n"; \
-} UPRV_BLOCK_MACRO_END
+#define PRINTMESG(msg) UPRV_BLOCK_MACRO_BEGIN { \
+ std::cout << "(" << __FILE__ << ":" << __LINE__ << ") " << msg << "\n"; \
+} UPRV_BLOCK_MACRO_END
#endif
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateIntervalInfo)
static const char gCalendarTag[]="calendar";
-static const char gGenericTag[]="generic";
+static const char gGenericTag[]="generic";
static const char gGregorianTag[]="gregorian";
static const char gIntervalDateTimePatternTag[]="intervalFormats";
static const char gFallbackPatternTag[]="fallback";
@@ -66,7 +66,7 @@ static const UChar gDefaultFallbackPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO,
DateIntervalInfo::DateIntervalInfo(UErrorCode& status)
: fFallbackIntervalPattern(gDefaultFallbackPattern),
fFirstDateInPtnIsLaterDate(false),
- fIntervalPatterns(nullptr)
+ fIntervalPatterns(nullptr)
{
fIntervalPatterns = initHash(status);
}
@@ -76,7 +76,7 @@ DateIntervalInfo::DateIntervalInfo(UErrorCode& status)
DateIntervalInfo::DateIntervalInfo(const Locale& locale, UErrorCode& status)
: fFallbackIntervalPattern(gDefaultFallbackPattern),
fFirstDateInPtnIsLaterDate(false),
- fIntervalPatterns(nullptr)
+ fIntervalPatterns(nullptr)
{
initializeData(locale, status);
}
@@ -126,7 +126,7 @@ DateIntervalInfo::setFallbackIntervalPattern(
DateIntervalInfo::DateIntervalInfo(const DateIntervalInfo& dtitvinf)
: UObject(dtitvinf),
- fIntervalPatterns(nullptr)
+ fIntervalPatterns(nullptr)
{
*this = dtitvinf;
}
@@ -161,7 +161,7 @@ DateIntervalInfo::clone() const {
DateIntervalInfo::~DateIntervalInfo() {
deleteHash(fIntervalPatterns);
- fIntervalPatterns = nullptr;
+ fIntervalPatterns = nullptr;
}
@@ -189,7 +189,7 @@ DateIntervalInfo::getIntervalPattern(const UnicodeString& skeleton,
}
const UnicodeString* patternsOfOneSkeleton = (UnicodeString*) fIntervalPatterns->get(skeleton);
- if ( patternsOfOneSkeleton != nullptr ) {
+ if ( patternsOfOneSkeleton != nullptr ) {
IntervalPatternIndex index = calendarFieldToIntervalIndex(field, status);
if ( U_FAILURE(status) ) {
return result;
@@ -329,9 +329,9 @@ struct DateIntervalInfo::DateIntervalSink : public ResourceSink {
char c0;
if ((c0 = patternLetter[0]) != 0 && patternLetter[1] == 0) {
// Check that the pattern letter is accepted
- if (c0 == 'G') {
- return UCAL_ERA;
- } else if (c0 == 'y') {
+ if (c0 == 'G') {
+ return UCAL_ERA;
+ } else if (c0 == 'y') {
return UCAL_YEAR;
} else if (c0 == 'M') {
return UCAL_MONTH;
@@ -363,7 +363,7 @@ struct DateIntervalInfo::DateIntervalSink : public ResourceSink {
UnicodeString* patternsOfOneSkeleton =
(UnicodeString*)(dateIntervalInfo.fIntervalPatterns->get(skeleton));
- if (patternsOfOneSkeleton == nullptr || patternsOfOneSkeleton[index].isEmpty()) {
+ if (patternsOfOneSkeleton == nullptr || patternsOfOneSkeleton[index].isEmpty()) {
UnicodeString pattern = value.getUnicodeString(errorCode);
dateIntervalInfo.setIntervalPatternInternally(skeleton, lrgDiffCalUnit,
pattern, errorCode);
@@ -398,8 +398,8 @@ DateIntervalInfo::initializeData(const Locale& locale, UErrorCode& status)
char calendarType[ULOC_KEYWORDS_CAPACITY]; // to be filled in with the type to use, if all goes well
char localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY];
// obtain a locale that always has the calendar key value that should be used
- (void)ures_getFunctionalEquivalent(localeWithCalendarKey, ULOC_LOCALE_IDENTIFIER_CAPACITY, nullptr,
- "calendar", "calendar", locName, nullptr, FALSE, &status);
+ (void)ures_getFunctionalEquivalent(localeWithCalendarKey, ULOC_LOCALE_IDENTIFIER_CAPACITY, nullptr,
+ "calendar", "calendar", locName, nullptr, FALSE, &status);
localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY-1] = 0; // ensure null termination
// now get the calendar key value from that locale
int32_t calendarTypeLen = uloc_getKeywordValue(localeWithCalendarKey, "calendar", calendarType,
@@ -411,47 +411,47 @@ DateIntervalInfo::initializeData(const Locale& locale, UErrorCode& status)
// Instantiate the resource bundles
UResourceBundle *rb, *calBundle;
- rb = ures_open(nullptr, locName, &status);
+ rb = ures_open(nullptr, locName, &status);
if (U_FAILURE(status)) {
return;
}
- calBundle = ures_getByKeyWithFallback(rb, gCalendarTag, nullptr, &status);
+ calBundle = ures_getByKeyWithFallback(rb, gCalendarTag, nullptr, &status);
if (U_SUCCESS(status)) {
UResourceBundle *calTypeBundle, *itvDtPtnResource;
// Get the fallback pattern
- const UChar* resStr = nullptr;
+ const UChar* resStr = nullptr;
int32_t resStrLen = 0;
- calTypeBundle = ures_getByKeyWithFallback(calBundle, calendarTypeToUse, nullptr, &status);
+ calTypeBundle = ures_getByKeyWithFallback(calBundle, calendarTypeToUse, nullptr, &status);
itvDtPtnResource = ures_getByKeyWithFallback(calTypeBundle,
- gIntervalDateTimePatternTag, nullptr, &status);
- // TODO(ICU-20400): After the fixing, we should find the "fallback" from
- // the rb directly by the path "calendar/${calendar}/intervalFormats/fallback".
+ gIntervalDateTimePatternTag, nullptr, &status);
+ // TODO(ICU-20400): After the fixing, we should find the "fallback" from
+ // the rb directly by the path "calendar/${calendar}/intervalFormats/fallback".
if ( U_SUCCESS(status) ) {
- resStr = ures_getStringByKeyWithFallback(itvDtPtnResource, gFallbackPatternTag,
- &resStrLen, &status);
- if ( U_FAILURE(status) ) {
- // Try to find "fallback" from "generic" to work around the bug in
- // ures_getByKeyWithFallback
- UErrorCode localStatus = U_ZERO_ERROR;
- UResourceBundle *genericCalBundle =
- ures_getByKeyWithFallback(calBundle, gGenericTag, nullptr, &localStatus);
- UResourceBundle *genericItvDtPtnResource =
- ures_getByKeyWithFallback(
- genericCalBundle, gIntervalDateTimePatternTag, nullptr, &localStatus);
- resStr = ures_getStringByKeyWithFallback(
- genericItvDtPtnResource, gFallbackPatternTag, &resStrLen, &localStatus);
- ures_close(genericItvDtPtnResource);
- ures_close(genericCalBundle);
- if ( U_SUCCESS(localStatus) ) {
- status = U_USING_FALLBACK_WARNING;;
- }
- }
- }
-
- if ( U_SUCCESS(status) && (resStr != nullptr)) {
+ resStr = ures_getStringByKeyWithFallback(itvDtPtnResource, gFallbackPatternTag,
+ &resStrLen, &status);
+ if ( U_FAILURE(status) ) {
+ // Try to find "fallback" from "generic" to work around the bug in
+ // ures_getByKeyWithFallback
+ UErrorCode localStatus = U_ZERO_ERROR;
+ UResourceBundle *genericCalBundle =
+ ures_getByKeyWithFallback(calBundle, gGenericTag, nullptr, &localStatus);
+ UResourceBundle *genericItvDtPtnResource =
+ ures_getByKeyWithFallback(
+ genericCalBundle, gIntervalDateTimePatternTag, nullptr, &localStatus);
+ resStr = ures_getStringByKeyWithFallback(
+ genericItvDtPtnResource, gFallbackPatternTag, &resStrLen, &localStatus);
+ ures_close(genericItvDtPtnResource);
+ ures_close(genericCalBundle);
+ if ( U_SUCCESS(localStatus) ) {
+ status = U_USING_FALLBACK_WARNING;;
+ }
+ }
+ }
+
+ if ( U_SUCCESS(status) && (resStr != nullptr)) {
UnicodeString pattern = UnicodeString(TRUE, resStr, resStrLen);
setFallbackIntervalPattern(pattern, status);
}
@@ -509,12 +509,12 @@ DateIntervalInfo::setIntervalPatternInternally(const UnicodeString& skeleton,
}
UnicodeString* patternsOfOneSkeleton = (UnicodeString*)(fIntervalPatterns->get(skeleton));
UBool emptyHash = false;
- if ( patternsOfOneSkeleton == nullptr ) {
+ if ( patternsOfOneSkeleton == nullptr ) {
patternsOfOneSkeleton = new UnicodeString[kIPI_MAX_INDEX];
- if (patternsOfOneSkeleton == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
+ if (patternsOfOneSkeleton == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
emptyHash = true;
}
@@ -612,7 +612,7 @@ DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton,
parseSkeleton(*inputSkeleton, inputSkeletonFieldWidth);
int32_t bestDistance = MAX_POSITIVE_INT;
- const UnicodeString* bestSkeleton = nullptr;
+ const UnicodeString* bestSkeleton = nullptr;
// 0 means exact the same skeletons;
// 1 means having the same field, but with different length,
@@ -622,10 +622,10 @@ DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton,
int8_t fieldLength = UPRV_LENGTHOF(skeletonFieldWidth);
int32_t pos = UHASH_FIRST;
- const UHashElement* elem = nullptr;
- while ( (elem = fIntervalPatterns->nextElement(pos)) != nullptr ) {
+ const UHashElement* elem = nullptr;
+ while ( (elem = fIntervalPatterns->nextElement(pos)) != nullptr ) {
const UHashTok keyTok = elem->key;
- UnicodeString* newSkeleton = (UnicodeString*)keyTok.pointer;
+ UnicodeString* newSkeleton = (UnicodeString*)keyTok.pointer;
#ifdef DTITVINF_DEBUG
skeleton->extract(0, skeleton->length(), result, "UTF-8");
sprintf(mesg, "available skeletons: skeleton: %s; \n", result);
@@ -637,7 +637,7 @@ DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton,
for ( i = 0; i < fieldLength; ++i ) {
skeletonFieldWidth[i] = 0;
}
- parseSkeleton(*newSkeleton, skeletonFieldWidth);
+ parseSkeleton(*newSkeleton, skeletonFieldWidth);
// calculate distance
int32_t distance = 0;
int8_t fieldDifference = 1;
@@ -663,7 +663,7 @@ DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton,
}
}
if ( distance < bestDistance ) {
- bestSkeleton = newSkeleton;
+ bestSkeleton = newSkeleton;
bestDistance = distance;
bestMatchDistanceInfo = fieldDifference;
}
@@ -715,9 +715,9 @@ DateIntervalInfo::calendarFieldToIntervalIndex(UCalendarDateFields field,
case UCAL_SECOND:
index = kIPI_SECOND;
break;
- case UCAL_MILLISECOND:
- index = kIPI_MILLISECOND;
- break;
+ case UCAL_MILLISECOND:
+ index = kIPI_MILLISECOND;
+ break;
default:
status = U_ILLEGAL_ARGUMENT_ERROR;
}
@@ -729,12 +729,12 @@ DateIntervalInfo::calendarFieldToIntervalIndex(UCalendarDateFields field,
void
DateIntervalInfo::deleteHash(Hashtable* hTable)
{
- if ( hTable == nullptr ) {
+ if ( hTable == nullptr ) {
return;
}
int32_t pos = UHASH_FIRST;
- const UHashElement* element = nullptr;
- while ( (element = hTable->nextElement(pos)) != nullptr ) {
+ const UHashElement* element = nullptr;
+ while ( (element = hTable->nextElement(pos)) != nullptr ) {
const UHashTok valueTok = element->value;
const UnicodeString* value = (UnicodeString*)valueTok.pointer;
delete[] value;
@@ -772,16 +772,16 @@ U_CDECL_END
Hashtable*
DateIntervalInfo::initHash(UErrorCode& status) {
if ( U_FAILURE(status) ) {
- return nullptr;
+ return nullptr;
}
Hashtable* hTable;
- if ( (hTable = new Hashtable(FALSE, status)) == nullptr ) {
+ if ( (hTable = new Hashtable(FALSE, status)) == nullptr ) {
status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
+ return nullptr;
}
if ( U_FAILURE(status) ) {
delete hTable;
- return nullptr;
+ return nullptr;
}
hTable->setValueComparator(dtitvinfHashTableValueComparator);
return hTable;
@@ -796,18 +796,18 @@ DateIntervalInfo::copyHash(const Hashtable* source,
return;
}
int32_t pos = UHASH_FIRST;
- const UHashElement* element = nullptr;
+ const UHashElement* element = nullptr;
if ( source ) {
- while ( (element = source->nextElement(pos)) != nullptr ) {
+ while ( (element = source->nextElement(pos)) != nullptr ) {
const UHashTok keyTok = element->key;
const UnicodeString* key = (UnicodeString*)keyTok.pointer;
const UHashTok valueTok = element->value;
const UnicodeString* value = (UnicodeString*)valueTok.pointer;
UnicodeString* copy = new UnicodeString[kIPI_MAX_INDEX];
- if (copy == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
+ if (copy == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
int8_t i;
for ( i = 0; i < kIPI_MAX_INDEX; ++i ) {
copy[i] = value[i];
diff --git a/contrib/libs/icu/i18n/dtptngen.cpp b/contrib/libs/icu/i18n/dtptngen.cpp
index 02be4f054b..992b0a869b 100644
--- a/contrib/libs/icu/i18n/dtptngen.cpp
+++ b/contrib/libs/icu/i18n/dtptngen.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -18,7 +18,7 @@
#include "unicode/decimfmt.h"
#include "unicode/dtfmtsym.h"
#include "unicode/dtptngen.h"
-#include "unicode/localpointer.h"
+#include "unicode/localpointer.h"
#include "unicode/simpleformatter.h"
#include "unicode/smpdtfmt.h"
#include "unicode/udat.h"
@@ -28,7 +28,7 @@
#include "unicode/ures.h"
#include "unicode/ustring.h"
#include "unicode/rep.h"
-#include "unicode/region.h"
+#include "unicode/region.h"
#include "cpputils.h"
#include "mutex.h"
#include "umutex.h"
@@ -90,17 +90,17 @@ static void ures_a_open(UResourceBundleAIterator *aiter, UResourceBundle *bund,
aiter->num = ures_getSize(aiter->bund);
aiter->cursor = 0;
#if !defined(U_SORT_ASCII_BUNDLE_ITERATOR)
- aiter->entries = nullptr;
+ aiter->entries = nullptr;
#else
aiter->entries = (UResAEntry*)uprv_malloc(sizeof(UResAEntry)*aiter->num);
for(int i=0;i<aiter->num;i++) {
- aiter->entries[i].item = ures_getByIndex(aiter->bund, i, nullptr, status);
+ aiter->entries[i].item = ures_getByIndex(aiter->bund, i, nullptr, status);
const char *akey = ures_getKey(aiter->entries[i].item);
int32_t len = uprv_strlen(akey)+1;
aiter->entries[i].key = (UChar*)uprv_malloc(len*sizeof(UChar));
u_charsToUChars(akey, aiter->entries[i].key, len);
}
- uprv_sortArray(aiter->entries, aiter->num, sizeof(UResAEntry), ures_a_codepointSort, nullptr, TRUE, status);
+ uprv_sortArray(aiter->entries, aiter->num, sizeof(UResAEntry), ures_a_codepointSort, nullptr, TRUE, status);
#endif
}
@@ -117,7 +117,7 @@ static const UChar *ures_a_getNextString(UResourceBundleAIterator *aiter, int32_
#if !defined(U_SORT_ASCII_BUNDLE_ITERATOR)
return ures_getNextString(aiter->bund, len, key, err);
#else
- if(U_FAILURE(*err)) return nullptr;
+ if(U_FAILURE(*err)) return nullptr;
UResourceBundle *item = aiter->entries[aiter->cursor].item;
const UChar* ret = ures_getString(item, len, err);
*key = ures_getKey(item);
@@ -136,18 +136,18 @@ U_NAMESPACE_BEGIN
// class DateTimePatternGenerator
// *****************************************************************************
static const UChar Canonical_Items[] = {
- // GyQMwWEDFdaHmsSv
- CAP_G, LOW_Y, CAP_Q, CAP_M, LOW_W, CAP_W, CAP_E,
- CAP_D, CAP_F, LOW_D, LOW_A, // The UDATPG_x_FIELD constants and these fields have a different order than in ICU4J
+ // GyQMwWEDFdaHmsSv
+ CAP_G, LOW_Y, CAP_Q, CAP_M, LOW_W, CAP_W, CAP_E,
+ CAP_D, CAP_F, LOW_D, LOW_A, // The UDATPG_x_FIELD constants and these fields have a different order than in ICU4J
CAP_H, LOW_M, LOW_S, CAP_S, LOW_V, 0
};
static const dtTypeElem dtTypes[] = {
// patternChar, field, type, minLen, weight
{CAP_G, UDATPG_ERA_FIELD, DT_SHORT, 1, 3,},
- {CAP_G, UDATPG_ERA_FIELD, DT_LONG, 4, 0},
- {CAP_G, UDATPG_ERA_FIELD, DT_NARROW, 5, 0},
-
+ {CAP_G, UDATPG_ERA_FIELD, DT_LONG, 4, 0},
+ {CAP_G, UDATPG_ERA_FIELD, DT_NARROW, 5, 0},
+
{LOW_Y, UDATPG_YEAR_FIELD, DT_NUMERIC, 1, 20},
{CAP_Y, UDATPG_YEAR_FIELD, DT_NUMERIC + DT_DELTA, 1, 20},
{LOW_U, UDATPG_YEAR_FIELD, DT_NUMERIC + 2*DT_DELTA, 1, 20},
@@ -155,16 +155,16 @@ static const dtTypeElem dtTypes[] = {
{CAP_U, UDATPG_YEAR_FIELD, DT_SHORT, 1, 3},
{CAP_U, UDATPG_YEAR_FIELD, DT_LONG, 4, 0},
{CAP_U, UDATPG_YEAR_FIELD, DT_NARROW, 5, 0},
-
+
{CAP_Q, UDATPG_QUARTER_FIELD, DT_NUMERIC, 1, 2},
{CAP_Q, UDATPG_QUARTER_FIELD, DT_SHORT, 3, 0},
{CAP_Q, UDATPG_QUARTER_FIELD, DT_LONG, 4, 0},
- {CAP_Q, UDATPG_QUARTER_FIELD, DT_NARROW, 5, 0},
+ {CAP_Q, UDATPG_QUARTER_FIELD, DT_NARROW, 5, 0},
{LOW_Q, UDATPG_QUARTER_FIELD, DT_NUMERIC + DT_DELTA, 1, 2},
- {LOW_Q, UDATPG_QUARTER_FIELD, DT_SHORT - DT_DELTA, 3, 0},
- {LOW_Q, UDATPG_QUARTER_FIELD, DT_LONG - DT_DELTA, 4, 0},
- {LOW_Q, UDATPG_QUARTER_FIELD, DT_NARROW - DT_DELTA, 5, 0},
-
+ {LOW_Q, UDATPG_QUARTER_FIELD, DT_SHORT - DT_DELTA, 3, 0},
+ {LOW_Q, UDATPG_QUARTER_FIELD, DT_LONG - DT_DELTA, 4, 0},
+ {LOW_Q, UDATPG_QUARTER_FIELD, DT_NARROW - DT_DELTA, 5, 0},
+
{CAP_M, UDATPG_MONTH_FIELD, DT_NUMERIC, 1, 2},
{CAP_M, UDATPG_MONTH_FIELD, DT_SHORT, 3, 0},
{CAP_M, UDATPG_MONTH_FIELD, DT_LONG, 4, 0},
@@ -174,66 +174,66 @@ static const dtTypeElem dtTypes[] = {
{CAP_L, UDATPG_MONTH_FIELD, DT_LONG - DT_DELTA, 4, 0},
{CAP_L, UDATPG_MONTH_FIELD, DT_NARROW - DT_DELTA, 5, 0},
{LOW_L, UDATPG_MONTH_FIELD, DT_NUMERIC + DT_DELTA, 1, 1},
-
+
{LOW_W, UDATPG_WEEK_OF_YEAR_FIELD, DT_NUMERIC, 1, 2},
-
- {CAP_W, UDATPG_WEEK_OF_MONTH_FIELD, DT_NUMERIC, 1, 0},
-
+
+ {CAP_W, UDATPG_WEEK_OF_MONTH_FIELD, DT_NUMERIC, 1, 0},
+
{CAP_E, UDATPG_WEEKDAY_FIELD, DT_SHORT, 1, 3},
{CAP_E, UDATPG_WEEKDAY_FIELD, DT_LONG, 4, 0},
{CAP_E, UDATPG_WEEKDAY_FIELD, DT_NARROW, 5, 0},
- {CAP_E, UDATPG_WEEKDAY_FIELD, DT_SHORTER, 6, 0},
+ {CAP_E, UDATPG_WEEKDAY_FIELD, DT_SHORTER, 6, 0},
{LOW_C, UDATPG_WEEKDAY_FIELD, DT_NUMERIC + 2*DT_DELTA, 1, 2},
{LOW_C, UDATPG_WEEKDAY_FIELD, DT_SHORT - 2*DT_DELTA, 3, 0},
{LOW_C, UDATPG_WEEKDAY_FIELD, DT_LONG - 2*DT_DELTA, 4, 0},
{LOW_C, UDATPG_WEEKDAY_FIELD, DT_NARROW - 2*DT_DELTA, 5, 0},
- {LOW_C, UDATPG_WEEKDAY_FIELD, DT_SHORTER - 2*DT_DELTA, 6, 0},
+ {LOW_C, UDATPG_WEEKDAY_FIELD, DT_SHORTER - 2*DT_DELTA, 6, 0},
{LOW_E, UDATPG_WEEKDAY_FIELD, DT_NUMERIC + DT_DELTA, 1, 2}, // LOW_E is currently not used in CLDR data, should not be canonical
{LOW_E, UDATPG_WEEKDAY_FIELD, DT_SHORT - DT_DELTA, 3, 0},
{LOW_E, UDATPG_WEEKDAY_FIELD, DT_LONG - DT_DELTA, 4, 0},
{LOW_E, UDATPG_WEEKDAY_FIELD, DT_NARROW - DT_DELTA, 5, 0},
- {LOW_E, UDATPG_WEEKDAY_FIELD, DT_SHORTER - DT_DELTA, 6, 0},
-
+ {LOW_E, UDATPG_WEEKDAY_FIELD, DT_SHORTER - DT_DELTA, 6, 0},
+
{LOW_D, UDATPG_DAY_FIELD, DT_NUMERIC, 1, 2},
- {LOW_G, UDATPG_DAY_FIELD, DT_NUMERIC + DT_DELTA, 1, 20}, // really internal use, so we don't care
-
- {CAP_D, UDATPG_DAY_OF_YEAR_FIELD, DT_NUMERIC, 1, 3},
-
- {CAP_F, UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, DT_NUMERIC, 1, 0},
-
- {LOW_A, UDATPG_DAYPERIOD_FIELD, DT_SHORT, 1, 3},
- {LOW_A, UDATPG_DAYPERIOD_FIELD, DT_LONG, 4, 0},
- {LOW_A, UDATPG_DAYPERIOD_FIELD, DT_NARROW, 5, 0},
- {LOW_B, UDATPG_DAYPERIOD_FIELD, DT_SHORT - DT_DELTA, 1, 3},
- {LOW_B, UDATPG_DAYPERIOD_FIELD, DT_LONG - DT_DELTA, 4, 0},
- {LOW_B, UDATPG_DAYPERIOD_FIELD, DT_NARROW - DT_DELTA, 5, 0},
- // b needs to be closer to a than to B, so we make this 3*DT_DELTA
- {CAP_B, UDATPG_DAYPERIOD_FIELD, DT_SHORT - 3*DT_DELTA, 1, 3},
- {CAP_B, UDATPG_DAYPERIOD_FIELD, DT_LONG - 3*DT_DELTA, 4, 0},
- {CAP_B, UDATPG_DAYPERIOD_FIELD, DT_NARROW - 3*DT_DELTA, 5, 0},
-
+ {LOW_G, UDATPG_DAY_FIELD, DT_NUMERIC + DT_DELTA, 1, 20}, // really internal use, so we don't care
+
+ {CAP_D, UDATPG_DAY_OF_YEAR_FIELD, DT_NUMERIC, 1, 3},
+
+ {CAP_F, UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, DT_NUMERIC, 1, 0},
+
+ {LOW_A, UDATPG_DAYPERIOD_FIELD, DT_SHORT, 1, 3},
+ {LOW_A, UDATPG_DAYPERIOD_FIELD, DT_LONG, 4, 0},
+ {LOW_A, UDATPG_DAYPERIOD_FIELD, DT_NARROW, 5, 0},
+ {LOW_B, UDATPG_DAYPERIOD_FIELD, DT_SHORT - DT_DELTA, 1, 3},
+ {LOW_B, UDATPG_DAYPERIOD_FIELD, DT_LONG - DT_DELTA, 4, 0},
+ {LOW_B, UDATPG_DAYPERIOD_FIELD, DT_NARROW - DT_DELTA, 5, 0},
+ // b needs to be closer to a than to B, so we make this 3*DT_DELTA
+ {CAP_B, UDATPG_DAYPERIOD_FIELD, DT_SHORT - 3*DT_DELTA, 1, 3},
+ {CAP_B, UDATPG_DAYPERIOD_FIELD, DT_LONG - 3*DT_DELTA, 4, 0},
+ {CAP_B, UDATPG_DAYPERIOD_FIELD, DT_NARROW - 3*DT_DELTA, 5, 0},
+
{CAP_H, UDATPG_HOUR_FIELD, DT_NUMERIC + 10*DT_DELTA, 1, 2}, // 24 hour
{LOW_K, UDATPG_HOUR_FIELD, DT_NUMERIC + 11*DT_DELTA, 1, 2}, // 24 hour
{LOW_H, UDATPG_HOUR_FIELD, DT_NUMERIC, 1, 2}, // 12 hour
{CAP_K, UDATPG_HOUR_FIELD, DT_NUMERIC + DT_DELTA, 1, 2}, // 12 hour
- // The C code has had versions of the following 3, keep & update. Should not need these, but...
- // Without these, certain tests using e.g. staticGetSkeleton fail because j/J in patterns
- // get skipped instead of mapped to the right hour chars, for example in
- // DateFormatTest::TestPatternFromSkeleton
- // IntlTestDateTimePatternGeneratorAPI:: testStaticGetSkeleton
- // DateIntervalFormatTest::testTicket11985
- // Need to investigate better handling of jJC replacement e.g. in staticGetSkeleton.
- {CAP_J, UDATPG_HOUR_FIELD, DT_NUMERIC + 5*DT_DELTA, 1, 2}, // 12/24 hour no AM/PM
- {LOW_J, UDATPG_HOUR_FIELD, DT_NUMERIC + 6*DT_DELTA, 1, 6}, // 12/24 hour
- {CAP_C, UDATPG_HOUR_FIELD, DT_NUMERIC + 7*DT_DELTA, 1, 6}, // 12/24 hour with preferred dayPeriods for 12
-
+ // The C code has had versions of the following 3, keep & update. Should not need these, but...
+ // Without these, certain tests using e.g. staticGetSkeleton fail because j/J in patterns
+ // get skipped instead of mapped to the right hour chars, for example in
+ // DateFormatTest::TestPatternFromSkeleton
+ // IntlTestDateTimePatternGeneratorAPI:: testStaticGetSkeleton
+ // DateIntervalFormatTest::testTicket11985
+ // Need to investigate better handling of jJC replacement e.g. in staticGetSkeleton.
+ {CAP_J, UDATPG_HOUR_FIELD, DT_NUMERIC + 5*DT_DELTA, 1, 2}, // 12/24 hour no AM/PM
+ {LOW_J, UDATPG_HOUR_FIELD, DT_NUMERIC + 6*DT_DELTA, 1, 6}, // 12/24 hour
+ {CAP_C, UDATPG_HOUR_FIELD, DT_NUMERIC + 7*DT_DELTA, 1, 6}, // 12/24 hour with preferred dayPeriods for 12
+
{LOW_M, UDATPG_MINUTE_FIELD, DT_NUMERIC, 1, 2},
-
+
{LOW_S, UDATPG_SECOND_FIELD, DT_NUMERIC, 1, 2},
- {CAP_A, UDATPG_SECOND_FIELD, DT_NUMERIC + DT_DELTA, 1, 1000},
-
- {CAP_S, UDATPG_FRACTIONAL_SECOND_FIELD, DT_NUMERIC, 1, 1000},
-
+ {CAP_A, UDATPG_SECOND_FIELD, DT_NUMERIC + DT_DELTA, 1, 1000},
+
+ {CAP_S, UDATPG_FRACTIONAL_SECOND_FIELD, DT_NUMERIC, 1, 1000},
+
{LOW_V, UDATPG_ZONE_FIELD, DT_SHORT - 2*DT_DELTA, 1, 0},
{LOW_V, UDATPG_ZONE_FIELD, DT_LONG - 2*DT_DELTA, 4, 0},
{LOW_Z, UDATPG_ZONE_FIELD, DT_SHORT, 1, 3},
@@ -245,39 +245,39 @@ static const dtTypeElem dtTypes[] = {
{CAP_O, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 4, 0},
{CAP_V, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 1, 0},
{CAP_V, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 2, 0},
- {CAP_V, UDATPG_ZONE_FIELD, DT_LONG-1 - DT_DELTA, 3, 0},
- {CAP_V, UDATPG_ZONE_FIELD, DT_LONG-2 - DT_DELTA, 4, 0},
+ {CAP_V, UDATPG_ZONE_FIELD, DT_LONG-1 - DT_DELTA, 3, 0},
+ {CAP_V, UDATPG_ZONE_FIELD, DT_LONG-2 - DT_DELTA, 4, 0},
{CAP_X, UDATPG_ZONE_FIELD, DT_NARROW - DT_DELTA, 1, 0},
{CAP_X, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 2, 0},
{CAP_X, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 4, 0},
{LOW_X, UDATPG_ZONE_FIELD, DT_NARROW - DT_DELTA, 1, 0},
{LOW_X, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 2, 0},
{LOW_X, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 4, 0},
-
+
{0, UDATPG_FIELD_COUNT, 0, 0, 0} , // last row of dtTypes[]
};
static const char* const CLDR_FIELD_APPEND[] = {
- "Era", "Year", "Quarter", "Month", "Week", "*", "Day-Of-Week",
- "*", "*", "Day", "*", // The UDATPG_x_FIELD constants and these fields have a different order than in ICU4J
+ "Era", "Year", "Quarter", "Month", "Week", "*", "Day-Of-Week",
+ "*", "*", "Day", "*", // The UDATPG_x_FIELD constants and these fields have a different order than in ICU4J
"Hour", "Minute", "Second", "*", "Timezone"
};
-static const char* const CLDR_FIELD_NAME[UDATPG_FIELD_COUNT] = {
- "era", "year", "quarter", "month", "week", "weekOfMonth", "weekday",
- "dayOfYear", "weekdayOfMonth", "day", "dayperiod", // The UDATPG_x_FIELD constants and these fields have a different order than in ICU4J
+static const char* const CLDR_FIELD_NAME[UDATPG_FIELD_COUNT] = {
+ "era", "year", "quarter", "month", "week", "weekOfMonth", "weekday",
+ "dayOfYear", "weekdayOfMonth", "day", "dayperiod", // The UDATPG_x_FIELD constants and these fields have a different order than in ICU4J
"hour", "minute", "second", "*", "zone"
};
-static const char* const CLDR_FIELD_WIDTH[] = { // [UDATPG_WIDTH_COUNT]
- "", "-short", "-narrow"
-};
-
-// TODO(ticket:13619): remove when definition uncommented in dtptngen.h.
-static const int32_t UDATPG_WIDTH_COUNT = UDATPG_NARROW + 1;
-static constexpr UDateTimePGDisplayWidth UDATPG_WIDTH_APPENDITEM = UDATPG_WIDE;
-static constexpr int32_t UDATPG_FIELD_KEY_MAX = 24; // max length of CLDR field tag (type + width)
-
+static const char* const CLDR_FIELD_WIDTH[] = { // [UDATPG_WIDTH_COUNT]
+ "", "-short", "-narrow"
+};
+
+// TODO(ticket:13619): remove when definition uncommented in dtptngen.h.
+static const int32_t UDATPG_WIDTH_COUNT = UDATPG_NARROW + 1;
+static constexpr UDateTimePGDisplayWidth UDATPG_WIDTH_APPENDITEM = UDATPG_WIDE;
+static constexpr int32_t UDATPG_FIELD_KEY_MAX = 24; // max length of CLDR field tag (type + width)
+
// For appendItems
static const UChar UDATPG_ItemFormat[]= {0x7B, 0x30, 0x7D, 0x20, 0x251C, 0x7B, 0x32, 0x7D, 0x3A,
0x20, 0x7B, 0x31, 0x7D, 0x2524, 0}; // {0} \u251C{2}: {1}\u2524
@@ -304,50 +304,50 @@ DateTimePatternGenerator::createInstance(UErrorCode& status) {
DateTimePatternGenerator* U_EXPORT2
DateTimePatternGenerator::createInstance(const Locale& locale, UErrorCode& status) {
if (U_FAILURE(status)) {
- return nullptr;
+ return nullptr;
}
LocalPointer<DateTimePatternGenerator> result(
new DateTimePatternGenerator(locale, status), status);
- return U_SUCCESS(status) ? result.orphan() : nullptr;
+ return U_SUCCESS(status) ? result.orphan() : nullptr;
}
DateTimePatternGenerator* U_EXPORT2
DateTimePatternGenerator::createEmptyInstance(UErrorCode& status) {
if (U_FAILURE(status)) {
- return nullptr;
+ return nullptr;
}
- LocalPointer<DateTimePatternGenerator> result(
- new DateTimePatternGenerator(status), status);
- return U_SUCCESS(status) ? result.orphan() : nullptr;
+ LocalPointer<DateTimePatternGenerator> result(
+ new DateTimePatternGenerator(status), status);
+ return U_SUCCESS(status) ? result.orphan() : nullptr;
}
DateTimePatternGenerator::DateTimePatternGenerator(UErrorCode &status) :
- skipMatcher(nullptr),
- fAvailableFormatKeyHash(nullptr),
- fDefaultHourFormatChar(0),
- internalErrorCode(U_ZERO_ERROR)
+ skipMatcher(nullptr),
+ fAvailableFormatKeyHash(nullptr),
+ fDefaultHourFormatChar(0),
+ internalErrorCode(U_ZERO_ERROR)
{
fp = new FormatParser();
dtMatcher = new DateTimeMatcher();
distanceInfo = new DistanceInfo();
patternMap = new PatternMap();
- if (fp == nullptr || dtMatcher == nullptr || distanceInfo == nullptr || patternMap == nullptr) {
- internalErrorCode = status = U_MEMORY_ALLOCATION_ERROR;
+ if (fp == nullptr || dtMatcher == nullptr || distanceInfo == nullptr || patternMap == nullptr) {
+ internalErrorCode = status = U_MEMORY_ALLOCATION_ERROR;
}
}
DateTimePatternGenerator::DateTimePatternGenerator(const Locale& locale, UErrorCode &status) :
- skipMatcher(nullptr),
- fAvailableFormatKeyHash(nullptr),
- fDefaultHourFormatChar(0),
- internalErrorCode(U_ZERO_ERROR)
+ skipMatcher(nullptr),
+ fAvailableFormatKeyHash(nullptr),
+ fDefaultHourFormatChar(0),
+ internalErrorCode(U_ZERO_ERROR)
{
fp = new FormatParser();
dtMatcher = new DateTimeMatcher();
distanceInfo = new DistanceInfo();
patternMap = new PatternMap();
- if (fp == nullptr || dtMatcher == nullptr || distanceInfo == nullptr || patternMap == nullptr) {
- internalErrorCode = status = U_MEMORY_ALLOCATION_ERROR;
+ if (fp == nullptr || dtMatcher == nullptr || distanceInfo == nullptr || patternMap == nullptr) {
+ internalErrorCode = status = U_MEMORY_ALLOCATION_ERROR;
}
else {
initData(locale, status);
@@ -356,18 +356,18 @@ DateTimePatternGenerator::DateTimePatternGenerator(const Locale& locale, UErrorC
DateTimePatternGenerator::DateTimePatternGenerator(const DateTimePatternGenerator& other) :
UObject(),
- skipMatcher(nullptr),
- fAvailableFormatKeyHash(nullptr),
- fDefaultHourFormatChar(0),
- internalErrorCode(U_ZERO_ERROR)
+ skipMatcher(nullptr),
+ fAvailableFormatKeyHash(nullptr),
+ fDefaultHourFormatChar(0),
+ internalErrorCode(U_ZERO_ERROR)
{
fp = new FormatParser();
dtMatcher = new DateTimeMatcher();
distanceInfo = new DistanceInfo();
patternMap = new PatternMap();
- if (fp == nullptr || dtMatcher == nullptr || distanceInfo == nullptr || patternMap == nullptr) {
- internalErrorCode = U_MEMORY_ALLOCATION_ERROR;
- }
+ if (fp == nullptr || dtMatcher == nullptr || distanceInfo == nullptr || patternMap == nullptr) {
+ internalErrorCode = U_MEMORY_ALLOCATION_ERROR;
+ }
*this=other;
}
@@ -377,7 +377,7 @@ DateTimePatternGenerator::operator=(const DateTimePatternGenerator& other) {
if (&other == this) {
return *this;
}
- internalErrorCode = other.internalErrorCode;
+ internalErrorCode = other.internalErrorCode;
pLocale = other.pLocale;
fDefaultHourFormatChar = other.fDefaultHourFormatChar;
*fp = *(other.fp);
@@ -389,27 +389,27 @@ DateTimePatternGenerator::operator=(const DateTimePatternGenerator& other) {
dateTimeFormat.getTerminatedBuffer();
decimal.getTerminatedBuffer();
delete skipMatcher;
- if ( other.skipMatcher == nullptr ) {
- skipMatcher = nullptr;
+ if ( other.skipMatcher == nullptr ) {
+ skipMatcher = nullptr;
}
else {
skipMatcher = new DateTimeMatcher(*other.skipMatcher);
- if (skipMatcher == nullptr)
- {
- internalErrorCode = U_MEMORY_ALLOCATION_ERROR;
- return *this;
- }
+ if (skipMatcher == nullptr)
+ {
+ internalErrorCode = U_MEMORY_ALLOCATION_ERROR;
+ return *this;
+ }
}
for (int32_t i=0; i< UDATPG_FIELD_COUNT; ++i ) {
appendItemFormats[i] = other.appendItemFormats[i];
- appendItemFormats[i].getTerminatedBuffer(); // NUL-terminate for the C API.
- for (int32_t j=0; j< UDATPG_WIDTH_COUNT; ++j ) {
- fieldDisplayNames[i][j] = other.fieldDisplayNames[i][j];
- fieldDisplayNames[i][j].getTerminatedBuffer(); // NUL-terminate for the C API.
- }
- }
- patternMap->copyFrom(*other.patternMap, internalErrorCode);
- copyHashtable(other.fAvailableFormatKeyHash, internalErrorCode);
+ appendItemFormats[i].getTerminatedBuffer(); // NUL-terminate for the C API.
+ for (int32_t j=0; j< UDATPG_WIDTH_COUNT; ++j ) {
+ fieldDisplayNames[i][j] = other.fieldDisplayNames[i][j];
+ fieldDisplayNames[i][j].getTerminatedBuffer(); // NUL-terminate for the C API.
+ }
+ }
+ patternMap->copyFrom(*other.patternMap, internalErrorCode);
+ copyHashtable(other.fAvailableFormatKeyHash, internalErrorCode);
return *this;
}
@@ -422,14 +422,14 @@ DateTimePatternGenerator::operator==(const DateTimePatternGenerator& other) cons
if ((pLocale==other.pLocale) && (patternMap->equals(*other.patternMap)) &&
(dateTimeFormat==other.dateTimeFormat) && (decimal==other.decimal)) {
for ( int32_t i=0 ; i<UDATPG_FIELD_COUNT; ++i ) {
- if (appendItemFormats[i] != other.appendItemFormats[i]) {
- return FALSE;
- }
- for (int32_t j=0; j< UDATPG_WIDTH_COUNT; ++j ) {
- if (fieldDisplayNames[i][j] != other.fieldDisplayNames[i][j]) {
- return FALSE;
- }
- }
+ if (appendItemFormats[i] != other.appendItemFormats[i]) {
+ return FALSE;
+ }
+ for (int32_t j=0; j< UDATPG_WIDTH_COUNT; ++j ) {
+ if (fieldDisplayNames[i][j] != other.fieldDisplayNames[i][j]) {
+ return FALSE;
+ }
+ }
}
return TRUE;
}
@@ -444,21 +444,21 @@ DateTimePatternGenerator::operator!=(const DateTimePatternGenerator& other) cons
}
DateTimePatternGenerator::~DateTimePatternGenerator() {
- if (fAvailableFormatKeyHash!=nullptr) {
+ if (fAvailableFormatKeyHash!=nullptr) {
delete fAvailableFormatKeyHash;
}
- if (fp != nullptr) delete fp;
- if (dtMatcher != nullptr) delete dtMatcher;
- if (distanceInfo != nullptr) delete distanceInfo;
- if (patternMap != nullptr) delete patternMap;
- if (skipMatcher != nullptr) delete skipMatcher;
+ if (fp != nullptr) delete fp;
+ if (dtMatcher != nullptr) delete dtMatcher;
+ if (distanceInfo != nullptr) delete distanceInfo;
+ if (patternMap != nullptr) delete patternMap;
+ if (skipMatcher != nullptr) delete skipMatcher;
}
namespace {
UInitOnce initOnce = U_INITONCE_INITIALIZER;
-UHashtable *localeToAllowedHourFormatsMap = nullptr;
+UHashtable *localeToAllowedHourFormatsMap = nullptr;
// Value deleter for hashmap.
U_CFUNC void U_CALLCONV deleteAllowedHourFormats(void *ptr) {
@@ -475,13 +475,13 @@ enum AllowedHourFormat{
ALLOWED_HOUR_FORMAT_UNKNOWN = -1,
ALLOWED_HOUR_FORMAT_h,
ALLOWED_HOUR_FORMAT_H,
- ALLOWED_HOUR_FORMAT_K, // Added ICU-20383, used by JP
- ALLOWED_HOUR_FORMAT_k, // Added ICU-20383, not currently used
+ ALLOWED_HOUR_FORMAT_K, // Added ICU-20383, used by JP
+ ALLOWED_HOUR_FORMAT_k, // Added ICU-20383, not currently used
ALLOWED_HOUR_FORMAT_hb,
- ALLOWED_HOUR_FORMAT_hB,
- ALLOWED_HOUR_FORMAT_Kb, // Added ICU-20383, not currently used
- ALLOWED_HOUR_FORMAT_KB, // Added ICU-20383, not currently used
- // ICU-20383 The following are unlikely and not currently used
+ ALLOWED_HOUR_FORMAT_hB,
+ ALLOWED_HOUR_FORMAT_Kb, // Added ICU-20383, not currently used
+ ALLOWED_HOUR_FORMAT_KB, // Added ICU-20383, not currently used
+ // ICU-20383 The following are unlikely and not currently used
ALLOWED_HOUR_FORMAT_Hb,
ALLOWED_HOUR_FORMAT_HB
};
@@ -492,8 +492,8 @@ void
DateTimePatternGenerator::initData(const Locale& locale, UErrorCode &status) {
//const char *baseLangName = locale.getBaseName(); // unused
- skipMatcher = nullptr;
- fAvailableFormatKeyHash=nullptr;
+ skipMatcher = nullptr;
+ fAvailableFormatKeyHash=nullptr;
addCanonicalItems(status);
addICUPatterns(locale, status);
addCLDRData(locale, status);
@@ -501,8 +501,8 @@ DateTimePatternGenerator::initData(const Locale& locale, UErrorCode &status) {
setDecimalSymbols(locale, status);
umtx_initOnce(initOnce, loadAllowedHourFormatsData, status);
getAllowedHourFormats(locale, status);
- // If any of the above methods failed then the object is in an invalid state.
- internalErrorCode = status;
+ // If any of the above methods failed then the object is in an invalid state.
+ internalErrorCode = status;
} // DateTimePatternGenerator::initData
namespace {
@@ -520,69 +520,69 @@ struct AllowedHourFormatsSink : public ResourceSink {
const char *regionOrLocale = key;
ResourceTable formatList = value.getTable(errorCode);
if (U_FAILURE(errorCode)) { return; }
- // below we construct a list[] that has an entry for the "preferred" value at [0],
- // followed by 1 or more entries for the "allowed" values, terminated with an
- // entry for ALLOWED_HOUR_FORMAT_UNKNOWN (not included in length below)
- LocalMemory<int32_t> list;
- int32_t length = 0;
- int32_t preferredFormat = ALLOWED_HOUR_FORMAT_UNKNOWN;
+ // below we construct a list[] that has an entry for the "preferred" value at [0],
+ // followed by 1 or more entries for the "allowed" values, terminated with an
+ // entry for ALLOWED_HOUR_FORMAT_UNKNOWN (not included in length below)
+ LocalMemory<int32_t> list;
+ int32_t length = 0;
+ int32_t preferredFormat = ALLOWED_HOUR_FORMAT_UNKNOWN;
for (int32_t j = 0; formatList.getKeyAndValue(j, key, value); ++j) {
- if (uprv_strcmp(key, "allowed") == 0) {
+ if (uprv_strcmp(key, "allowed") == 0) {
if (value.getType() == URES_STRING) {
- length = 2; // 1 preferred to add later, 1 allowed to add now
- if (list.allocateInsteadAndReset(length + 1) == nullptr) {
+ length = 2; // 1 preferred to add later, 1 allowed to add now
+ if (list.allocateInsteadAndReset(length + 1) == nullptr) {
errorCode = U_MEMORY_ALLOCATION_ERROR;
return;
}
- list[1] = getHourFormatFromUnicodeString(value.getUnicodeString(errorCode));
+ list[1] = getHourFormatFromUnicodeString(value.getUnicodeString(errorCode));
}
else {
ResourceArray allowedFormats = value.getArray(errorCode);
- length = allowedFormats.getSize() + 1; // 1 preferred, getSize allowed
- if (list.allocateInsteadAndReset(length + 1) == nullptr) {
+ length = allowedFormats.getSize() + 1; // 1 preferred, getSize allowed
+ if (list.allocateInsteadAndReset(length + 1) == nullptr) {
errorCode = U_MEMORY_ALLOCATION_ERROR;
return;
}
- for (int32_t k = 1; k < length; ++k) {
- allowedFormats.getValue(k-1, value);
+ for (int32_t k = 1; k < length; ++k) {
+ allowedFormats.getValue(k-1, value);
list[k] = getHourFormatFromUnicodeString(value.getUnicodeString(errorCode));
}
}
- } else if (uprv_strcmp(key, "preferred") == 0) {
- preferredFormat = getHourFormatFromUnicodeString(value.getUnicodeString(errorCode));
+ } else if (uprv_strcmp(key, "preferred") == 0) {
+ preferredFormat = getHourFormatFromUnicodeString(value.getUnicodeString(errorCode));
}
}
- if (length > 1) {
- list[0] = (preferredFormat!=ALLOWED_HOUR_FORMAT_UNKNOWN)? preferredFormat: list[1];
- } else {
- // fallback handling for missing data
- length = 2; // 1 preferred, 1 allowed
- if (list.allocateInsteadAndReset(length + 1) == nullptr) {
- errorCode = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- list[0] = (preferredFormat!=ALLOWED_HOUR_FORMAT_UNKNOWN)? preferredFormat: ALLOWED_HOUR_FORMAT_H;
- list[1] = list[0];
- }
- list[length] = ALLOWED_HOUR_FORMAT_UNKNOWN;
- // At this point list[] will have at least two non-ALLOWED_HOUR_FORMAT_UNKNOWN entries,
- // followed by ALLOWED_HOUR_FORMAT_UNKNOWN.
- uhash_put(localeToAllowedHourFormatsMap, const_cast<char *>(regionOrLocale), list.orphan(), &errorCode);
- if (U_FAILURE(errorCode)) { return; }
- }
- }
-
- AllowedHourFormat getHourFormatFromUnicodeString(const UnicodeString &s) {
+ if (length > 1) {
+ list[0] = (preferredFormat!=ALLOWED_HOUR_FORMAT_UNKNOWN)? preferredFormat: list[1];
+ } else {
+ // fallback handling for missing data
+ length = 2; // 1 preferred, 1 allowed
+ if (list.allocateInsteadAndReset(length + 1) == nullptr) {
+ errorCode = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ list[0] = (preferredFormat!=ALLOWED_HOUR_FORMAT_UNKNOWN)? preferredFormat: ALLOWED_HOUR_FORMAT_H;
+ list[1] = list[0];
+ }
+ list[length] = ALLOWED_HOUR_FORMAT_UNKNOWN;
+ // At this point list[] will have at least two non-ALLOWED_HOUR_FORMAT_UNKNOWN entries,
+ // followed by ALLOWED_HOUR_FORMAT_UNKNOWN.
+ uhash_put(localeToAllowedHourFormatsMap, const_cast<char *>(regionOrLocale), list.orphan(), &errorCode);
+ if (U_FAILURE(errorCode)) { return; }
+ }
+ }
+
+ AllowedHourFormat getHourFormatFromUnicodeString(const UnicodeString &s) {
if (s.length() == 1) {
if (s[0] == LOW_H) { return ALLOWED_HOUR_FORMAT_h; }
if (s[0] == CAP_H) { return ALLOWED_HOUR_FORMAT_H; }
- if (s[0] == CAP_K) { return ALLOWED_HOUR_FORMAT_K; }
- if (s[0] == LOW_K) { return ALLOWED_HOUR_FORMAT_k; }
+ if (s[0] == CAP_K) { return ALLOWED_HOUR_FORMAT_K; }
+ if (s[0] == LOW_K) { return ALLOWED_HOUR_FORMAT_k; }
} else if (s.length() == 2) {
if (s[0] == LOW_H && s[1] == LOW_B) { return ALLOWED_HOUR_FORMAT_hb; }
- if (s[0] == LOW_H && s[1] == CAP_B) { return ALLOWED_HOUR_FORMAT_hB; }
- if (s[0] == CAP_K && s[1] == LOW_B) { return ALLOWED_HOUR_FORMAT_Kb; }
- if (s[0] == CAP_K && s[1] == CAP_B) { return ALLOWED_HOUR_FORMAT_KB; }
+ if (s[0] == LOW_H && s[1] == CAP_B) { return ALLOWED_HOUR_FORMAT_hB; }
+ if (s[0] == CAP_K && s[1] == LOW_B) { return ALLOWED_HOUR_FORMAT_Kb; }
+ if (s[0] == CAP_K && s[1] == CAP_B) { return ALLOWED_HOUR_FORMAT_KB; }
if (s[0] == CAP_H && s[1] == LOW_B) { return ALLOWED_HOUR_FORMAT_Hb; }
if (s[0] == CAP_H && s[1] == CAP_B) { return ALLOWED_HOUR_FORMAT_HB; }
}
@@ -598,15 +598,15 @@ AllowedHourFormatsSink::~AllowedHourFormatsSink() {}
U_CFUNC void U_CALLCONV DateTimePatternGenerator::loadAllowedHourFormatsData(UErrorCode &status) {
if (U_FAILURE(status)) { return; }
localeToAllowedHourFormatsMap = uhash_open(
- uhash_hashChars, uhash_compareChars, nullptr, &status);
- if (U_FAILURE(status)) { return; }
-
+ uhash_hashChars, uhash_compareChars, nullptr, &status);
+ if (U_FAILURE(status)) { return; }
+
uhash_setValueDeleter(localeToAllowedHourFormatsMap, deleteAllowedHourFormats);
- ucln_i18n_registerCleanup(UCLN_I18N_ALLOWED_HOUR_FORMATS, allowedHourFormatsCleanup);
-
- LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "supplementalData", &status));
- if (U_FAILURE(status)) { return; }
+ ucln_i18n_registerCleanup(UCLN_I18N_ALLOWED_HOUR_FORMATS, allowedHourFormatsCleanup);
+ LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "supplementalData", &status));
+ if (U_FAILURE(status)) { return; }
+
AllowedHourFormatsSink sink;
// TODO: Currently in the enumeration each table allocates a new array.
// Try to reduce the number of memory allocations. Consider storing a
@@ -614,136 +614,136 @@ U_CFUNC void U_CALLCONV DateTimePatternGenerator::loadAllowedHourFormatsData(UEr
// into the hashmap, store 6 single-value sub-arrays right at the beginning of the
// vector (at index enum*2) for easy data sharing, copy sub-arrays into runtime
// object. Remember to clean up the vector, too.
- ures_getAllItemsWithFallback(rb.getAlias(), "timeData", sink, status);
-}
-
-static int32_t* getAllowedHourFormatsLangCountry(const char* language, const char* country, UErrorCode& status) {
- CharString langCountry;
- langCountry.append(language, status);
- langCountry.append('_', status);
- langCountry.append(country, status);
-
- int32_t* allowedFormats;
- allowedFormats = (int32_t *)uhash_get(localeToAllowedHourFormatsMap, langCountry.data());
- if (allowedFormats == nullptr) {
- allowedFormats = (int32_t *)uhash_get(localeToAllowedHourFormatsMap, const_cast<char *>(country));
- }
-
- return allowedFormats;
+ ures_getAllItemsWithFallback(rb.getAlias(), "timeData", sink, status);
+}
+
+static int32_t* getAllowedHourFormatsLangCountry(const char* language, const char* country, UErrorCode& status) {
+ CharString langCountry;
+ langCountry.append(language, status);
+ langCountry.append('_', status);
+ langCountry.append(country, status);
+
+ int32_t* allowedFormats;
+ allowedFormats = (int32_t *)uhash_get(localeToAllowedHourFormatsMap, langCountry.data());
+ if (allowedFormats == nullptr) {
+ allowedFormats = (int32_t *)uhash_get(localeToAllowedHourFormatsMap, const_cast<char *>(country));
+ }
+
+ return allowedFormats;
}
void DateTimePatternGenerator::getAllowedHourFormats(const Locale &locale, UErrorCode &status) {
if (U_FAILURE(status)) { return; }
-
- const char *language = locale.getLanguage();
- const char *country = locale.getCountry();
- Locale maxLocale; // must be here for correct lifetime
- if (*language == '\0' || *country == '\0') {
- maxLocale = locale;
- UErrorCode localStatus = U_ZERO_ERROR;
- maxLocale.addLikelySubtags(localStatus);
- if (U_SUCCESS(localStatus)) {
- language = maxLocale.getLanguage();
- country = maxLocale.getCountry();
- }
- }
- if (*language == '\0') {
- // Unexpected, but fail gracefully
- language = "und";
- }
- if (*country == '\0') {
- country = "001";
- }
-
- int32_t* allowedFormats = getAllowedHourFormatsLangCountry(language, country, status);
-
- // We need to check if there is an hour cycle on locale
- char buffer[8];
- int32_t count = locale.getKeywordValue("hours", buffer, sizeof(buffer), status);
-
- fDefaultHourFormatChar = 0;
- if (U_SUCCESS(status) && count > 0) {
- if(uprv_strcmp(buffer, "h24") == 0) {
- fDefaultHourFormatChar = LOW_K;
- } else if(uprv_strcmp(buffer, "h23") == 0) {
- fDefaultHourFormatChar = CAP_H;
- } else if(uprv_strcmp(buffer, "h12") == 0) {
- fDefaultHourFormatChar = LOW_H;
- } else if(uprv_strcmp(buffer, "h11") == 0) {
- fDefaultHourFormatChar = CAP_K;
- }
- }
-
- // Check if the region has an alias
- if (allowedFormats == nullptr) {
- UErrorCode localStatus = U_ZERO_ERROR;
- const Region* region = Region::getInstance(country, localStatus);
- if (U_SUCCESS(localStatus)) {
- country = region->getRegionCode(); // the real region code
- allowedFormats = getAllowedHourFormatsLangCountry(language, country, status);
- }
- }
-
- if (allowedFormats != nullptr) { // Lookup is successful
- // Here allowedFormats points to a list consisting of key for preferredFormat,
- // followed by one or more keys for allowedFormats, then followed by ALLOWED_HOUR_FORMAT_UNKNOWN.
- if (!fDefaultHourFormatChar) {
- switch (allowedFormats[0]) {
- case ALLOWED_HOUR_FORMAT_h: fDefaultHourFormatChar = LOW_H; break;
- case ALLOWED_HOUR_FORMAT_H: fDefaultHourFormatChar = CAP_H; break;
- case ALLOWED_HOUR_FORMAT_K: fDefaultHourFormatChar = CAP_K; break;
- case ALLOWED_HOUR_FORMAT_k: fDefaultHourFormatChar = LOW_K; break;
- default: fDefaultHourFormatChar = CAP_H; break;
- }
- }
-
+
+ const char *language = locale.getLanguage();
+ const char *country = locale.getCountry();
+ Locale maxLocale; // must be here for correct lifetime
+ if (*language == '\0' || *country == '\0') {
+ maxLocale = locale;
+ UErrorCode localStatus = U_ZERO_ERROR;
+ maxLocale.addLikelySubtags(localStatus);
+ if (U_SUCCESS(localStatus)) {
+ language = maxLocale.getLanguage();
+ country = maxLocale.getCountry();
+ }
+ }
+ if (*language == '\0') {
+ // Unexpected, but fail gracefully
+ language = "und";
+ }
+ if (*country == '\0') {
+ country = "001";
+ }
+
+ int32_t* allowedFormats = getAllowedHourFormatsLangCountry(language, country, status);
+
+ // We need to check if there is an hour cycle on locale
+ char buffer[8];
+ int32_t count = locale.getKeywordValue("hours", buffer, sizeof(buffer), status);
+
+ fDefaultHourFormatChar = 0;
+ if (U_SUCCESS(status) && count > 0) {
+ if(uprv_strcmp(buffer, "h24") == 0) {
+ fDefaultHourFormatChar = LOW_K;
+ } else if(uprv_strcmp(buffer, "h23") == 0) {
+ fDefaultHourFormatChar = CAP_H;
+ } else if(uprv_strcmp(buffer, "h12") == 0) {
+ fDefaultHourFormatChar = LOW_H;
+ } else if(uprv_strcmp(buffer, "h11") == 0) {
+ fDefaultHourFormatChar = CAP_K;
+ }
+ }
+
+ // Check if the region has an alias
+ if (allowedFormats == nullptr) {
+ UErrorCode localStatus = U_ZERO_ERROR;
+ const Region* region = Region::getInstance(country, localStatus);
+ if (U_SUCCESS(localStatus)) {
+ country = region->getRegionCode(); // the real region code
+ allowedFormats = getAllowedHourFormatsLangCountry(language, country, status);
+ }
+ }
+
+ if (allowedFormats != nullptr) { // Lookup is successful
+ // Here allowedFormats points to a list consisting of key for preferredFormat,
+ // followed by one or more keys for allowedFormats, then followed by ALLOWED_HOUR_FORMAT_UNKNOWN.
+ if (!fDefaultHourFormatChar) {
+ switch (allowedFormats[0]) {
+ case ALLOWED_HOUR_FORMAT_h: fDefaultHourFormatChar = LOW_H; break;
+ case ALLOWED_HOUR_FORMAT_H: fDefaultHourFormatChar = CAP_H; break;
+ case ALLOWED_HOUR_FORMAT_K: fDefaultHourFormatChar = CAP_K; break;
+ case ALLOWED_HOUR_FORMAT_k: fDefaultHourFormatChar = LOW_K; break;
+ default: fDefaultHourFormatChar = CAP_H; break;
+ }
+ }
+
for (int32_t i = 0; i < UPRV_LENGTHOF(fAllowedHourFormats); ++i) {
- fAllowedHourFormats[i] = allowedFormats[i + 1];
- if (fAllowedHourFormats[i] == ALLOWED_HOUR_FORMAT_UNKNOWN) {
+ fAllowedHourFormats[i] = allowedFormats[i + 1];
+ if (fAllowedHourFormats[i] == ALLOWED_HOUR_FORMAT_UNKNOWN) {
break;
}
}
} else { // Lookup failed, twice
- if (!fDefaultHourFormatChar) {
- fDefaultHourFormatChar = CAP_H;
- }
+ if (!fDefaultHourFormatChar) {
+ fDefaultHourFormatChar = CAP_H;
+ }
fAllowedHourFormats[0] = ALLOWED_HOUR_FORMAT_H;
fAllowedHourFormats[1] = ALLOWED_HOUR_FORMAT_UNKNOWN;
}
}
-UDateFormatHourCycle
-DateTimePatternGenerator::getDefaultHourCycle(UErrorCode& status) const {
- if (U_FAILURE(status)) {
- return UDAT_HOUR_CYCLE_23;
- }
- if (fDefaultHourFormatChar == 0) {
- // We need to return something, but the caller should ignore it
- // anyways since the returned status is a failure.
- status = U_UNSUPPORTED_ERROR;
- return UDAT_HOUR_CYCLE_23;
- }
- switch (fDefaultHourFormatChar) {
- case CAP_K:
- return UDAT_HOUR_CYCLE_11;
- case LOW_H:
- return UDAT_HOUR_CYCLE_12;
- case CAP_H:
- return UDAT_HOUR_CYCLE_23;
- case LOW_K:
- return UDAT_HOUR_CYCLE_24;
- default:
- UPRV_UNREACHABLE;
- }
-}
-
+UDateFormatHourCycle
+DateTimePatternGenerator::getDefaultHourCycle(UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return UDAT_HOUR_CYCLE_23;
+ }
+ if (fDefaultHourFormatChar == 0) {
+ // We need to return something, but the caller should ignore it
+ // anyways since the returned status is a failure.
+ status = U_UNSUPPORTED_ERROR;
+ return UDAT_HOUR_CYCLE_23;
+ }
+ switch (fDefaultHourFormatChar) {
+ case CAP_K:
+ return UDAT_HOUR_CYCLE_11;
+ case LOW_H:
+ return UDAT_HOUR_CYCLE_12;
+ case CAP_H:
+ return UDAT_HOUR_CYCLE_23;
+ case LOW_K:
+ return UDAT_HOUR_CYCLE_24;
+ default:
+ UPRV_UNREACHABLE;
+ }
+}
+
UnicodeString
DateTimePatternGenerator::getSkeleton(const UnicodeString& pattern, UErrorCode&
/*status*/) {
- FormatParser fp2;
+ FormatParser fp2;
DateTimeMatcher matcher;
PtnSkeleton localSkeleton;
- matcher.set(pattern, &fp2, localSkeleton);
+ matcher.set(pattern, &fp2, localSkeleton);
return localSkeleton.getSkeleton();
}
@@ -759,10 +759,10 @@ DateTimePatternGenerator::staticGetSkeleton(
UnicodeString
DateTimePatternGenerator::getBaseSkeleton(const UnicodeString& pattern, UErrorCode& /*status*/) {
- FormatParser fp2;
+ FormatParser fp2;
DateTimeMatcher matcher;
PtnSkeleton localSkeleton;
- matcher.set(pattern, &fp2, localSkeleton);
+ matcher.set(pattern, &fp2, localSkeleton);
return localSkeleton.getBaseSkeleton();
}
@@ -788,7 +788,7 @@ DateTimePatternGenerator::addICUPatterns(const Locale& locale, UErrorCode& statu
DateFormat::EStyle style = (DateFormat::EStyle)i;
df = DateFormat::createDateInstance(style, locale);
SimpleDateFormat* sdf;
- if (df != nullptr && (sdf = dynamic_cast<SimpleDateFormat*>(df)) != nullptr) {
+ if (df != nullptr && (sdf = dynamic_cast<SimpleDateFormat*>(df)) != nullptr) {
sdf->toPattern(dfPattern);
addPattern(dfPattern, FALSE, conflictingString, status);
}
@@ -797,7 +797,7 @@ DateTimePatternGenerator::addICUPatterns(const Locale& locale, UErrorCode& statu
if (U_FAILURE(status)) { return; }
df = DateFormat::createTimeInstance(style, locale);
- if (df != nullptr && (sdf = dynamic_cast<SimpleDateFormat*>(df)) != nullptr) {
+ if (df != nullptr && (sdf = dynamic_cast<SimpleDateFormat*>(df)) != nullptr) {
sdf->toPattern(dfPattern);
addPattern(dfPattern, FALSE, conflictingString, status);
@@ -865,19 +865,19 @@ void
DateTimePatternGenerator::getCalendarTypeToUse(const Locale& locale, CharString& destination, UErrorCode& err) {
destination.clear().append(DT_DateTimeGregorianTag, -1, err); // initial default
if ( U_SUCCESS(err) ) {
- UErrorCode localStatus = U_ZERO_ERROR;
+ UErrorCode localStatus = U_ZERO_ERROR;
char localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY];
// obtain a locale that always has the calendar key value that should be used
ures_getFunctionalEquivalent(
localeWithCalendarKey,
ULOC_LOCALE_IDENTIFIER_CAPACITY,
- nullptr,
+ nullptr,
"calendar",
"calendar",
locale.getName(),
- nullptr,
+ nullptr,
FALSE,
- &localStatus);
+ &localStatus);
localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY-1] = 0; // ensure null termination
// now get the calendar key value from that locale
char calendarType[ULOC_KEYWORDS_CAPACITY];
@@ -886,14 +886,14 @@ DateTimePatternGenerator::getCalendarTypeToUse(const Locale& locale, CharString&
"calendar",
calendarType,
ULOC_KEYWORDS_CAPACITY,
- &localStatus);
- // If the input locale was invalid, don't fail with missing resource error, instead
- // continue with default of Gregorian.
- if (U_FAILURE(localStatus) && localStatus != U_MISSING_RESOURCE_ERROR) {
- err = localStatus;
- return;
- }
- if (calendarTypeLen < ULOC_KEYWORDS_CAPACITY) {
+ &localStatus);
+ // If the input locale was invalid, don't fail with missing resource error, instead
+ // continue with default of Gregorian.
+ if (U_FAILURE(localStatus) && localStatus != U_MISSING_RESOURCE_ERROR) {
+ err = localStatus;
+ return;
+ }
+ if (calendarTypeLen < ULOC_KEYWORDS_CAPACITY) {
destination.clear().append(calendarType, -1, err);
if (U_FAILURE(err)) { return; }
}
@@ -903,10 +903,10 @@ DateTimePatternGenerator::getCalendarTypeToUse(const Locale& locale, CharString&
void
DateTimePatternGenerator::consumeShortTimePattern(const UnicodeString& shortTimePattern,
UErrorCode& status) {
- if (U_FAILURE(status)) { return; }
- // ICU-20383 No longer set fDefaultHourFormatChar to the hour format character from
- // this pattern; instead it is set from localeToAllowedHourFormatsMap which now
- // includes entries for both preferred and allowed formats.
+ if (U_FAILURE(status)) { return; }
+ // ICU-20383 No longer set fDefaultHourFormatChar to the hour format character from
+ // this pattern; instead it is set from localeToAllowedHourFormatsMap which now
+ // includes entries for both preferred and allowed formats.
// HACK for hh:ss
hackTimes(shortTimePattern, status);
@@ -958,16 +958,16 @@ struct DateTimePatternGenerator::AppendItemNamesSink : public ResourceSink {
ResourceTable itemsTable = value.getTable(errorCode);
if (U_FAILURE(errorCode)) { return; }
for (int32_t i = 0; itemsTable.getKeyAndValue(i, key, value); ++i) {
- UDateTimePGDisplayWidth width;
- UDateTimePatternField field = dtpg.getFieldAndWidthIndices(key, &width);
+ UDateTimePGDisplayWidth width;
+ UDateTimePatternField field = dtpg.getFieldAndWidthIndices(key, &width);
if (field == UDATPG_FIELD_COUNT) { continue; }
ResourceTable detailsTable = value.getTable(errorCode);
if (U_FAILURE(errorCode)) { return; }
for (int32_t j = 0; detailsTable.getKeyAndValue(j, key, value); ++j) {
if (uprv_strcmp(key, "dn") != 0) { continue; }
const UnicodeString& valueStr = value.getUnicodeString(errorCode);
- if (dtpg.getFieldDisplayName(field,width).isEmpty() && !valueStr.isEmpty()) {
- dtpg.setFieldDisplayName(field,width,valueStr);
+ if (dtpg.getFieldDisplayName(field,width).isEmpty() && !valueStr.isEmpty()) {
+ dtpg.setFieldDisplayName(field,width,valueStr);
}
break;
}
@@ -976,7 +976,7 @@ struct DateTimePatternGenerator::AppendItemNamesSink : public ResourceSink {
void fillInMissing() {
for (int32_t i = 0; i < UDATPG_FIELD_COUNT; i++) {
- UnicodeString& valueStr = dtpg.getMutableFieldDisplayName((UDateTimePatternField)i, UDATPG_WIDE);
+ UnicodeString& valueStr = dtpg.getMutableFieldDisplayName((UDateTimePatternField)i, UDATPG_WIDE);
if (valueStr.isEmpty()) {
valueStr = CAP_F;
U_ASSERT(i < 20);
@@ -991,12 +991,12 @@ struct DateTimePatternGenerator::AppendItemNamesSink : public ResourceSink {
// NUL-terminate for the C API.
valueStr.getTerminatedBuffer();
}
- for (int32_t j = 1; j < UDATPG_WIDTH_COUNT; j++) {
- UnicodeString& valueStr2 = dtpg.getMutableFieldDisplayName((UDateTimePatternField)i, (UDateTimePGDisplayWidth)j);
- if (valueStr2.isEmpty()) {
- valueStr2 = dtpg.getFieldDisplayName((UDateTimePatternField)i, (UDateTimePGDisplayWidth)(j-1));
- }
- }
+ for (int32_t j = 1; j < UDATPG_WIDTH_COUNT; j++) {
+ UnicodeString& valueStr2 = dtpg.getMutableFieldDisplayName((UDateTimePatternField)i, (UDateTimePGDisplayWidth)j);
+ if (valueStr2.isEmpty()) {
+ valueStr2 = dtpg.getFieldDisplayName((UDateTimePatternField)i, (UDateTimePGDisplayWidth)(j-1));
+ }
+ }
}
}
};
@@ -1041,7 +1041,7 @@ DateTimePatternGenerator::addCLDRData(const Locale& locale, UErrorCode& errorCod
UnicodeString rbPattern, value, field;
CharString path;
- LocalUResourceBundlePointer rb(ures_open(nullptr, locale.getName(), &errorCode));
+ LocalUResourceBundlePointer rb(ures_open(nullptr, locale.getName(), &errorCode));
if (U_FAILURE(errorCode)) { return; }
CharString calendarTypeToUse; // to be filled in with the type to use, if all goes well
@@ -1086,13 +1086,13 @@ DateTimePatternGenerator::addCLDRData(const Locale& locale, UErrorCode& errorCod
void
DateTimePatternGenerator::initHashtable(UErrorCode& err) {
- if (U_FAILURE(err)) { return; }
- if (fAvailableFormatKeyHash!=nullptr) {
+ if (U_FAILURE(err)) { return; }
+ if (fAvailableFormatKeyHash!=nullptr) {
return;
}
- LocalPointer<Hashtable> hash(new Hashtable(FALSE, err), err);
- if (U_SUCCESS(err)) {
- fAvailableFormatKeyHash = hash.orphan();
+ LocalPointer<Hashtable> hash(new Hashtable(FALSE, err), err);
+ if (U_SUCCESS(err)) {
+ fAvailableFormatKeyHash = hash.orphan();
}
}
@@ -1110,35 +1110,35 @@ DateTimePatternGenerator::getAppendItemFormat(UDateTimePatternField field) const
void
DateTimePatternGenerator::setAppendItemName(UDateTimePatternField field, const UnicodeString& value) {
- setFieldDisplayName(field, UDATPG_WIDTH_APPENDITEM, value);
+ setFieldDisplayName(field, UDATPG_WIDTH_APPENDITEM, value);
}
const UnicodeString&
DateTimePatternGenerator::getAppendItemName(UDateTimePatternField field) const {
- return fieldDisplayNames[field][UDATPG_WIDTH_APPENDITEM];
-}
-
-void
-DateTimePatternGenerator::setFieldDisplayName(UDateTimePatternField field, UDateTimePGDisplayWidth width, const UnicodeString& value) {
- fieldDisplayNames[field][width] = value;
- // NUL-terminate for the C API.
- fieldDisplayNames[field][width].getTerminatedBuffer();
-}
-
-UnicodeString
-DateTimePatternGenerator::getFieldDisplayName(UDateTimePatternField field, UDateTimePGDisplayWidth width) const {
- return fieldDisplayNames[field][width];
-}
-
+ return fieldDisplayNames[field][UDATPG_WIDTH_APPENDITEM];
+}
+
+void
+DateTimePatternGenerator::setFieldDisplayName(UDateTimePatternField field, UDateTimePGDisplayWidth width, const UnicodeString& value) {
+ fieldDisplayNames[field][width] = value;
+ // NUL-terminate for the C API.
+ fieldDisplayNames[field][width].getTerminatedBuffer();
+}
+
+UnicodeString
+DateTimePatternGenerator::getFieldDisplayName(UDateTimePatternField field, UDateTimePGDisplayWidth width) const {
+ return fieldDisplayNames[field][width];
+}
+
UnicodeString&
-DateTimePatternGenerator::getMutableFieldDisplayName(UDateTimePatternField field, UDateTimePGDisplayWidth width) {
- return fieldDisplayNames[field][width];
+DateTimePatternGenerator::getMutableFieldDisplayName(UDateTimePatternField field, UDateTimePGDisplayWidth width) {
+ return fieldDisplayNames[field][width];
}
void
DateTimePatternGenerator::getAppendName(UDateTimePatternField field, UnicodeString& value) {
value = SINGLE_QUOTE;
- value += fieldDisplayNames[field][UDATPG_WIDTH_APPENDITEM];
+ value += fieldDisplayNames[field][UDATPG_WIDTH_APPENDITEM];
value += SINGLE_QUOTE;
}
@@ -1149,14 +1149,14 @@ DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UErro
UnicodeString
DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UDateTimePatternMatchOptions options, UErrorCode& status) {
- if (U_FAILURE(status)) {
- return UnicodeString();
- }
- if (U_FAILURE(internalErrorCode)) {
- status = internalErrorCode;
- return UnicodeString();
- }
- const UnicodeString *bestPattern = nullptr;
+ if (U_FAILURE(status)) {
+ return UnicodeString();
+ }
+ if (U_FAILURE(internalErrorCode)) {
+ status = internalErrorCode;
+ return UnicodeString();
+ }
+ const UnicodeString *bestPattern = nullptr;
UnicodeString dtFormat;
UnicodeString resultPattern;
int32_t flags = kDTPGNoFlags;
@@ -1165,17 +1165,17 @@ DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UDate
int32_t timeMask=(1<<UDATPG_FIELD_COUNT) - 1 - dateMask;
// Replace hour metacharacters 'j', 'C' and 'J', set flags as necessary
- UnicodeString patternFormMapped = mapSkeletonMetacharacters(patternForm, &flags, status);
- if (U_FAILURE(status)) {
- return UnicodeString();
- }
+ UnicodeString patternFormMapped = mapSkeletonMetacharacters(patternForm, &flags, status);
+ if (U_FAILURE(status)) {
+ return UnicodeString();
+ }
- resultPattern.remove();
- dtMatcher->set(patternFormMapped, fp);
- const PtnSkeleton* specifiedSkeleton = nullptr;
- bestPattern=getBestRaw(*dtMatcher, -1, distanceInfo, status, &specifiedSkeleton);
- if (U_FAILURE(status)) {
- return UnicodeString();
+ resultPattern.remove();
+ dtMatcher->set(patternFormMapped, fp);
+ const PtnSkeleton* specifiedSkeleton = nullptr;
+ bestPattern=getBestRaw(*dtMatcher, -1, distanceInfo, status, &specifiedSkeleton);
+ if (U_FAILURE(status)) {
+ return UnicodeString();
}
if ( distanceInfo->missingFieldMask==0 && distanceInfo->extraFieldMask==0 ) {
@@ -1184,11 +1184,11 @@ DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UDate
return resultPattern;
}
int32_t neededFields = dtMatcher->getFieldMask();
- UnicodeString datePattern=getBestAppending(neededFields & dateMask, flags, status, options);
- UnicodeString timePattern=getBestAppending(neededFields & timeMask, flags, status, options);
- if (U_FAILURE(status)) {
- return UnicodeString();
- }
+ UnicodeString datePattern=getBestAppending(neededFields & dateMask, flags, status, options);
+ UnicodeString timePattern=getBestAppending(neededFields & timeMask, flags, status, options);
+ if (U_FAILURE(status)) {
+ return UnicodeString();
+ }
if (datePattern.length()==0) {
if (timePattern.length()==0) {
resultPattern.remove();
@@ -1207,87 +1207,87 @@ DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UDate
return resultPattern;
}
-/*
- * Map a skeleton that may have metacharacters jJC to one without, by replacing
- * the metacharacters with locale-appropriate fields of h/H/k/K and of a/b/B
- * (depends on fDefaultHourFormatChar and fAllowedHourFormats being set, which in
- * turn depends on initData having been run). This method also updates the flags
- * as necessary. Returns the updated skeleton.
- */
-UnicodeString
-DateTimePatternGenerator::mapSkeletonMetacharacters(const UnicodeString& patternForm, int32_t* flags, UErrorCode& status) {
- UnicodeString patternFormMapped;
- patternFormMapped.remove();
- UBool inQuoted = FALSE;
- int32_t patPos, patLen = patternForm.length();
- for (patPos = 0; patPos < patLen; patPos++) {
- UChar patChr = patternForm.charAt(patPos);
- if (patChr == SINGLE_QUOTE) {
- inQuoted = !inQuoted;
- } else if (!inQuoted) {
- // Handle special mappings for 'j' and 'C' in which fields lengths
- // 1,3,5 => hour field length 1
- // 2,4,6 => hour field length 2
- // 1,2 => abbreviated dayPeriod (field length 1..3)
- // 3,4 => long dayPeriod (field length 4)
- // 5,6 => narrow dayPeriod (field length 5)
- if (patChr == LOW_J || patChr == CAP_C) {
- int32_t extraLen = 0; // 1 less than total field length
- while (patPos+1 < patLen && patternForm.charAt(patPos+1)==patChr) {
- extraLen++;
- patPos++;
- }
- int32_t hourLen = 1 + (extraLen & 1);
- int32_t dayPeriodLen = (extraLen < 2)? 1: 3 + (extraLen >> 1);
- UChar hourChar = LOW_H;
- UChar dayPeriodChar = LOW_A;
- if (patChr == LOW_J) {
- hourChar = fDefaultHourFormatChar;
- } else {
- AllowedHourFormat bestAllowed;
- if (fAllowedHourFormats[0] != ALLOWED_HOUR_FORMAT_UNKNOWN) {
- bestAllowed = (AllowedHourFormat)fAllowedHourFormats[0];
- } else {
- status = U_INVALID_FORMAT_ERROR;
- return UnicodeString();
- }
- if (bestAllowed == ALLOWED_HOUR_FORMAT_H || bestAllowed == ALLOWED_HOUR_FORMAT_HB || bestAllowed == ALLOWED_HOUR_FORMAT_Hb) {
- hourChar = CAP_H;
- } else if (bestAllowed == ALLOWED_HOUR_FORMAT_K || bestAllowed == ALLOWED_HOUR_FORMAT_KB || bestAllowed == ALLOWED_HOUR_FORMAT_Kb) {
- hourChar = CAP_K;
- } else if (bestAllowed == ALLOWED_HOUR_FORMAT_k) {
- hourChar = LOW_K;
- }
- // in #13183 just add b/B to skeleton, no longer need to set special flags
- if (bestAllowed == ALLOWED_HOUR_FORMAT_HB || bestAllowed == ALLOWED_HOUR_FORMAT_hB || bestAllowed == ALLOWED_HOUR_FORMAT_KB) {
- dayPeriodChar = CAP_B;
- } else if (bestAllowed == ALLOWED_HOUR_FORMAT_Hb || bestAllowed == ALLOWED_HOUR_FORMAT_hb || bestAllowed == ALLOWED_HOUR_FORMAT_Kb) {
- dayPeriodChar = LOW_B;
- }
- }
- if (hourChar==CAP_H || hourChar==LOW_K) {
- dayPeriodLen = 0;
- }
- while (dayPeriodLen-- > 0) {
- patternFormMapped.append(dayPeriodChar);
- }
- while (hourLen-- > 0) {
- patternFormMapped.append(hourChar);
- }
- } else if (patChr == CAP_J) {
- // Get pattern for skeleton with H, then replace H or k
- // with fDefaultHourFormatChar (if different)
- patternFormMapped.append(CAP_H);
- *flags |= kDTPGSkeletonUsesCapJ;
- } else {
- patternFormMapped.append(patChr);
- }
- }
- }
- return patternFormMapped;
-}
-
+/*
+ * Map a skeleton that may have metacharacters jJC to one without, by replacing
+ * the metacharacters with locale-appropriate fields of h/H/k/K and of a/b/B
+ * (depends on fDefaultHourFormatChar and fAllowedHourFormats being set, which in
+ * turn depends on initData having been run). This method also updates the flags
+ * as necessary. Returns the updated skeleton.
+ */
UnicodeString
+DateTimePatternGenerator::mapSkeletonMetacharacters(const UnicodeString& patternForm, int32_t* flags, UErrorCode& status) {
+ UnicodeString patternFormMapped;
+ patternFormMapped.remove();
+ UBool inQuoted = FALSE;
+ int32_t patPos, patLen = patternForm.length();
+ for (patPos = 0; patPos < patLen; patPos++) {
+ UChar patChr = patternForm.charAt(patPos);
+ if (patChr == SINGLE_QUOTE) {
+ inQuoted = !inQuoted;
+ } else if (!inQuoted) {
+ // Handle special mappings for 'j' and 'C' in which fields lengths
+ // 1,3,5 => hour field length 1
+ // 2,4,6 => hour field length 2
+ // 1,2 => abbreviated dayPeriod (field length 1..3)
+ // 3,4 => long dayPeriod (field length 4)
+ // 5,6 => narrow dayPeriod (field length 5)
+ if (patChr == LOW_J || patChr == CAP_C) {
+ int32_t extraLen = 0; // 1 less than total field length
+ while (patPos+1 < patLen && patternForm.charAt(patPos+1)==patChr) {
+ extraLen++;
+ patPos++;
+ }
+ int32_t hourLen = 1 + (extraLen & 1);
+ int32_t dayPeriodLen = (extraLen < 2)? 1: 3 + (extraLen >> 1);
+ UChar hourChar = LOW_H;
+ UChar dayPeriodChar = LOW_A;
+ if (patChr == LOW_J) {
+ hourChar = fDefaultHourFormatChar;
+ } else {
+ AllowedHourFormat bestAllowed;
+ if (fAllowedHourFormats[0] != ALLOWED_HOUR_FORMAT_UNKNOWN) {
+ bestAllowed = (AllowedHourFormat)fAllowedHourFormats[0];
+ } else {
+ status = U_INVALID_FORMAT_ERROR;
+ return UnicodeString();
+ }
+ if (bestAllowed == ALLOWED_HOUR_FORMAT_H || bestAllowed == ALLOWED_HOUR_FORMAT_HB || bestAllowed == ALLOWED_HOUR_FORMAT_Hb) {
+ hourChar = CAP_H;
+ } else if (bestAllowed == ALLOWED_HOUR_FORMAT_K || bestAllowed == ALLOWED_HOUR_FORMAT_KB || bestAllowed == ALLOWED_HOUR_FORMAT_Kb) {
+ hourChar = CAP_K;
+ } else if (bestAllowed == ALLOWED_HOUR_FORMAT_k) {
+ hourChar = LOW_K;
+ }
+ // in #13183 just add b/B to skeleton, no longer need to set special flags
+ if (bestAllowed == ALLOWED_HOUR_FORMAT_HB || bestAllowed == ALLOWED_HOUR_FORMAT_hB || bestAllowed == ALLOWED_HOUR_FORMAT_KB) {
+ dayPeriodChar = CAP_B;
+ } else if (bestAllowed == ALLOWED_HOUR_FORMAT_Hb || bestAllowed == ALLOWED_HOUR_FORMAT_hb || bestAllowed == ALLOWED_HOUR_FORMAT_Kb) {
+ dayPeriodChar = LOW_B;
+ }
+ }
+ if (hourChar==CAP_H || hourChar==LOW_K) {
+ dayPeriodLen = 0;
+ }
+ while (dayPeriodLen-- > 0) {
+ patternFormMapped.append(dayPeriodChar);
+ }
+ while (hourLen-- > 0) {
+ patternFormMapped.append(hourChar);
+ }
+ } else if (patChr == CAP_J) {
+ // Get pattern for skeleton with H, then replace H or k
+ // with fDefaultHourFormatChar (if different)
+ patternFormMapped.append(CAP_H);
+ *flags |= kDTPGSkeletonUsesCapJ;
+ } else {
+ patternFormMapped.append(patChr);
+ }
+ }
+ }
+ return patternFormMapped;
+}
+
+UnicodeString
DateTimePatternGenerator::replaceFieldTypes(const UnicodeString& pattern,
const UnicodeString& skeleton,
UErrorCode& status) {
@@ -1298,16 +1298,16 @@ UnicodeString
DateTimePatternGenerator::replaceFieldTypes(const UnicodeString& pattern,
const UnicodeString& skeleton,
UDateTimePatternMatchOptions options,
- UErrorCode& status) {
- if (U_FAILURE(status)) {
- return UnicodeString();
- }
- if (U_FAILURE(internalErrorCode)) {
- status = internalErrorCode;
- return UnicodeString();
- }
+ UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return UnicodeString();
+ }
+ if (U_FAILURE(internalErrorCode)) {
+ status = internalErrorCode;
+ return UnicodeString();
+ }
dtMatcher->set(skeleton, fp);
- UnicodeString result = adjustFieldTypes(pattern, nullptr, kDTPGNoFlags, options);
+ UnicodeString result = adjustFieldTypes(pattern, nullptr, kDTPGNoFlags, options);
return result;
}
@@ -1350,24 +1350,24 @@ DateTimePatternGenerator::getDateTimeFormat() const {
void
DateTimePatternGenerator::setDateTimeFromCalendar(const Locale& locale, UErrorCode& status) {
- if (U_FAILURE(status)) { return; }
-
+ if (U_FAILURE(status)) { return; }
+
const UChar *resStr;
int32_t resStrLen = 0;
- LocalPointer<Calendar> fCalendar(Calendar::createInstance(locale, status), status);
+ LocalPointer<Calendar> fCalendar(Calendar::createInstance(locale, status), status);
if (U_FAILURE(status)) { return; }
- LocalUResourceBundlePointer calData(ures_open(nullptr, locale.getBaseName(), &status));
- if (U_FAILURE(status)) { return; }
+ LocalUResourceBundlePointer calData(ures_open(nullptr, locale.getBaseName(), &status));
+ if (U_FAILURE(status)) { return; }
ures_getByKey(calData.getAlias(), DT_DateTimeCalendarTag, calData.getAlias(), &status);
- if (U_FAILURE(status)) { return; }
+ if (U_FAILURE(status)) { return; }
LocalUResourceBundlePointer dateTimePatterns;
- if (fCalendar->getType() != nullptr && *fCalendar->getType() != '\0'
+ if (fCalendar->getType() != nullptr && *fCalendar->getType() != '\0'
&& uprv_strcmp(fCalendar->getType(), DT_DateTimeGregorianTag) != 0) {
dateTimePatterns.adoptInstead(ures_getByKeyWithFallback(calData.getAlias(), fCalendar->getType(),
- nullptr, &status));
+ nullptr, &status));
ures_getByKeyWithFallback(dateTimePatterns.getAlias(), DT_DateTimePatternsTag,
dateTimePatterns.getAlias(), &status);
}
@@ -1407,12 +1407,12 @@ DateTimePatternGenerator::addPattern(
UnicodeString &conflictingPattern,
UErrorCode& status)
{
- if (U_FAILURE(internalErrorCode)) {
- status = internalErrorCode;
- return UDATPG_NO_CONFLICT;
- }
-
- return addPatternWithSkeleton(pattern, nullptr, override, conflictingPattern, status);
+ if (U_FAILURE(internalErrorCode)) {
+ status = internalErrorCode;
+ return UDATPG_NO_CONFLICT;
+ }
+
+ return addPatternWithSkeleton(pattern, nullptr, override, conflictingPattern, status);
}
// For DateTimePatternGenerator::addPatternWithSkeleton -
@@ -1433,17 +1433,17 @@ DateTimePatternGenerator::addPatternWithSkeleton(
UnicodeString& conflictingPattern,
UErrorCode& status)
{
- if (U_FAILURE(internalErrorCode)) {
- status = internalErrorCode;
- return UDATPG_NO_CONFLICT;
- }
+ if (U_FAILURE(internalErrorCode)) {
+ status = internalErrorCode;
+ return UDATPG_NO_CONFLICT;
+ }
UnicodeString basePattern;
PtnSkeleton skeleton;
UDateTimePatternConflict conflictingStatus = UDATPG_NO_CONFLICT;
DateTimeMatcher matcher;
- if ( skeletonToUse == nullptr ) {
+ if ( skeletonToUse == nullptr ) {
matcher.set(pattern, fp, skeleton);
matcher.getBasePattern(basePattern);
} else {
@@ -1459,7 +1459,7 @@ DateTimePatternGenerator::addPatternWithSkeleton(
// availableFormats items from root, which should not override any previous entry with the same base.
UBool entryHadSpecifiedSkeleton;
const UnicodeString *duplicatePattern = patternMap->getPatternFromBasePattern(basePattern, entryHadSpecifiedSkeleton);
- if (duplicatePattern != nullptr && (!entryHadSpecifiedSkeleton || (skeletonToUse != nullptr && !override))) {
+ if (duplicatePattern != nullptr && (!entryHadSpecifiedSkeleton || (skeletonToUse != nullptr && !override))) {
conflictingStatus = UDATPG_BASE_CONFLICT;
conflictingPattern = *duplicatePattern;
if (!override) {
@@ -1470,16 +1470,16 @@ DateTimePatternGenerator::addPatternWithSkeleton(
// items from CLDR data. In that case, we don't want an item from a parent locale to replace an item with
// same skeleton from the specified locale, so skip the current item if skeletonWasSpecified is true for
// the previously-specified conflicting item.
- const PtnSkeleton* entrySpecifiedSkeleton = nullptr;
+ const PtnSkeleton* entrySpecifiedSkeleton = nullptr;
duplicatePattern = patternMap->getPatternFromSkeleton(skeleton, &entrySpecifiedSkeleton);
- if (duplicatePattern != nullptr ) {
+ if (duplicatePattern != nullptr ) {
conflictingStatus = UDATPG_CONFLICT;
conflictingPattern = *duplicatePattern;
- if (!override || (skeletonToUse != nullptr && entrySpecifiedSkeleton != nullptr)) {
+ if (!override || (skeletonToUse != nullptr && entrySpecifiedSkeleton != nullptr)) {
return conflictingStatus;
}
}
- patternMap->add(basePattern, skeleton, pattern, skeletonToUse != nullptr, status);
+ patternMap->add(basePattern, skeleton, pattern, skeletonToUse != nullptr, status);
if(U_FAILURE(status)) {
return conflictingStatus;
}
@@ -1499,23 +1499,23 @@ DateTimePatternGenerator::getAppendFormatNumber(const char* field) const {
}
UDateTimePatternField
-DateTimePatternGenerator::getFieldAndWidthIndices(const char* key, UDateTimePGDisplayWidth* widthP) const {
- char cldrFieldKey[UDATPG_FIELD_KEY_MAX + 1];
- uprv_strncpy(cldrFieldKey, key, UDATPG_FIELD_KEY_MAX);
- cldrFieldKey[UDATPG_FIELD_KEY_MAX]=0; // ensure termination
- *widthP = UDATPG_WIDE;
- char* hyphenPtr = uprv_strchr(cldrFieldKey, '-');
- if (hyphenPtr) {
- for (int32_t i=UDATPG_WIDTH_COUNT-1; i>0; --i) {
- if (uprv_strcmp(CLDR_FIELD_WIDTH[i], hyphenPtr)==0) {
- *widthP=(UDateTimePGDisplayWidth)i;
- break;
- }
- }
- *hyphenPtr = 0; // now delete width portion of key
- }
+DateTimePatternGenerator::getFieldAndWidthIndices(const char* key, UDateTimePGDisplayWidth* widthP) const {
+ char cldrFieldKey[UDATPG_FIELD_KEY_MAX + 1];
+ uprv_strncpy(cldrFieldKey, key, UDATPG_FIELD_KEY_MAX);
+ cldrFieldKey[UDATPG_FIELD_KEY_MAX]=0; // ensure termination
+ *widthP = UDATPG_WIDE;
+ char* hyphenPtr = uprv_strchr(cldrFieldKey, '-');
+ if (hyphenPtr) {
+ for (int32_t i=UDATPG_WIDTH_COUNT-1; i>0; --i) {
+ if (uprv_strcmp(CLDR_FIELD_WIDTH[i], hyphenPtr)==0) {
+ *widthP=(UDateTimePGDisplayWidth)i;
+ break;
+ }
+ }
+ *hyphenPtr = 0; // now delete width portion of key
+ }
for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) {
- if (uprv_strcmp(CLDR_FIELD_NAME[i],cldrFieldKey)==0) {
+ if (uprv_strcmp(CLDR_FIELD_NAME[i],cldrFieldKey)==0) {
return (UDateTimePatternField)i;
}
}
@@ -1526,32 +1526,32 @@ const UnicodeString*
DateTimePatternGenerator::getBestRaw(DateTimeMatcher& source,
int32_t includeMask,
DistanceInfo* missingFields,
- UErrorCode &status,
+ UErrorCode &status,
const PtnSkeleton** specifiedSkeletonPtr) {
int32_t bestDistance = 0x7fffffff;
- int32_t bestMissingFieldMask = -1;
+ int32_t bestMissingFieldMask = -1;
DistanceInfo tempInfo;
- const UnicodeString *bestPattern=nullptr;
- const PtnSkeleton* specifiedSkeleton=nullptr;
-
- PatternMapIterator it(status);
- if (U_FAILURE(status)) { return nullptr; }
+ const UnicodeString *bestPattern=nullptr;
+ const PtnSkeleton* specifiedSkeleton=nullptr;
+ PatternMapIterator it(status);
+ if (U_FAILURE(status)) { return nullptr; }
+
for (it.set(*patternMap); it.hasNext(); ) {
DateTimeMatcher trial = it.next();
if (trial.equals(skipMatcher)) {
continue;
}
int32_t distance=source.getDistance(trial, includeMask, tempInfo);
- // Because we iterate over a map the order is undefined. Can change between implementations,
- // versions, and will very likely be different between Java and C/C++.
- // So if we have patterns with the same distance we also look at the missingFieldMask,
- // and we favour the smallest one. Because the field is a bitmask this technically means we
- // favour differences in the "least significant fields". For example we prefer the one with differences
- // in seconds field vs one with difference in the hours field.
- if (distance<bestDistance || (distance==bestDistance && bestMissingFieldMask<tempInfo.missingFieldMask)) {
+ // Because we iterate over a map the order is undefined. Can change between implementations,
+ // versions, and will very likely be different between Java and C/C++.
+ // So if we have patterns with the same distance we also look at the missingFieldMask,
+ // and we favour the smallest one. Because the field is a bitmask this technically means we
+ // favour differences in the "least significant fields". For example we prefer the one with differences
+ // in seconds field vs one with difference in the hours field.
+ if (distance<bestDistance || (distance==bestDistance && bestMissingFieldMask<tempInfo.missingFieldMask)) {
bestDistance=distance;
- bestMissingFieldMask=tempInfo.missingFieldMask;
+ bestMissingFieldMask=tempInfo.missingFieldMask;
bestPattern=patternMap->getPatternFromSkeleton(*trial.getSkeletonPtr(), &specifiedSkeleton);
missingFields->setTo(tempInfo);
if (distance==0) {
@@ -1597,23 +1597,23 @@ DateTimePatternGenerator::adjustFieldTypes(const UnicodeString& pattern,
const dtTypeElem *row = &dtTypes[canonicalIndex];
int32_t typeValue = row->field;
- // handle day periods - with #13183, no longer need special handling here, integrated with normal types
+ // handle day periods - with #13183, no longer need special handling here, integrated with normal types
if ((flags & kDTPGFixFractionalSeconds) != 0 && typeValue == UDATPG_SECOND_FIELD) {
field += decimal;
dtMatcher->skeleton.original.appendFieldTo(UDATPG_FRACTIONAL_SECOND_FIELD, field);
} else if (dtMatcher->skeleton.type[typeValue]!=0) {
// Here:
- // - "reqField" is the field from the originally requested skeleton after replacement
- // of metacharacters 'j', 'C' and 'J', with length "reqFieldLen".
+ // - "reqField" is the field from the originally requested skeleton after replacement
+ // of metacharacters 'j', 'C' and 'J', with length "reqFieldLen".
// - "field" is the field from the found pattern.
//
// The adjusted field should consist of characters from the originally requested
- // skeleton, except in the case of UDATPG_MONTH_FIELD or
+ // skeleton, except in the case of UDATPG_MONTH_FIELD or
// UDATPG_WEEKDAY_FIELD or UDATPG_YEAR_FIELD, in which case it should consist
- // of characters from the found pattern. In some cases of UDATPG_HOUR_FIELD,
- // there is adjustment following the "defaultHourFormatChar". There is explanation
- // how it is done below.
+ // of characters from the found pattern. In some cases of UDATPG_HOUR_FIELD,
+ // there is adjustment following the "defaultHourFormatChar". There is explanation
+ // how it is done below.
//
// The length of the adjusted field (adjFieldLen) should match that in the originally
// requested skeleton, except that in the following cases the length of the adjusted field
@@ -1651,31 +1651,31 @@ DateTimePatternGenerator::adjustFieldTypes(const UnicodeString& pattern,
&& (typeValue!= UDATPG_YEAR_FIELD || reqFieldChar==CAP_Y))
? reqFieldChar
: field.charAt(0);
- if (typeValue == UDATPG_HOUR_FIELD && fDefaultHourFormatChar != 0) {
- // The adjustment here is required to match spec (https://www.unicode.org/reports/tr35/tr35-dates.html#dfst-hour).
- // It is necessary to match the hour-cycle preferred by the Locale.
- // Given that, we need to do the following adjustments:
- // 1. When hour-cycle is h11 it should replace 'h' by 'K'.
- // 2. When hour-cycle is h23 it should replace 'H' by 'k'.
- // 3. When hour-cycle is h24 it should replace 'k' by 'H'.
- // 4. When hour-cycle is h12 it should replace 'K' by 'h'.
-
- if ((flags & kDTPGSkeletonUsesCapJ) != 0 || reqFieldChar == fDefaultHourFormatChar) {
- c = fDefaultHourFormatChar;
- } else if (reqFieldChar == LOW_H && fDefaultHourFormatChar == CAP_K) {
- c = CAP_K;
- } else if (reqFieldChar == CAP_H && fDefaultHourFormatChar == LOW_K) {
- c = LOW_K;
- } else if (reqFieldChar == LOW_K && fDefaultHourFormatChar == CAP_H) {
- c = CAP_H;
- } else if (reqFieldChar == CAP_K && fDefaultHourFormatChar == LOW_H) {
- c = LOW_H;
- }
+ if (typeValue == UDATPG_HOUR_FIELD && fDefaultHourFormatChar != 0) {
+ // The adjustment here is required to match spec (https://www.unicode.org/reports/tr35/tr35-dates.html#dfst-hour).
+ // It is necessary to match the hour-cycle preferred by the Locale.
+ // Given that, we need to do the following adjustments:
+ // 1. When hour-cycle is h11 it should replace 'h' by 'K'.
+ // 2. When hour-cycle is h23 it should replace 'H' by 'k'.
+ // 3. When hour-cycle is h24 it should replace 'k' by 'H'.
+ // 4. When hour-cycle is h12 it should replace 'K' by 'h'.
+
+ if ((flags & kDTPGSkeletonUsesCapJ) != 0 || reqFieldChar == fDefaultHourFormatChar) {
+ c = fDefaultHourFormatChar;
+ } else if (reqFieldChar == LOW_H && fDefaultHourFormatChar == CAP_K) {
+ c = CAP_K;
+ } else if (reqFieldChar == CAP_H && fDefaultHourFormatChar == LOW_K) {
+ c = LOW_K;
+ } else if (reqFieldChar == LOW_K && fDefaultHourFormatChar == CAP_H) {
+ c = CAP_H;
+ } else if (reqFieldChar == CAP_K && fDefaultHourFormatChar == LOW_H) {
+ c = LOW_H;
+ }
}
-
+
field.remove();
- for (int32_t j=adjFieldLen; j>0; --j) {
- field += c;
+ for (int32_t j=adjFieldLen; j>0; --j) {
+ field += c;
}
}
newPattern+=field;
@@ -1685,21 +1685,21 @@ DateTimePatternGenerator::adjustFieldTypes(const UnicodeString& pattern,
}
UnicodeString
-DateTimePatternGenerator::getBestAppending(int32_t missingFields, int32_t flags, UErrorCode &status, UDateTimePatternMatchOptions options) {
- if (U_FAILURE(status)) {
- return UnicodeString();
- }
+DateTimePatternGenerator::getBestAppending(int32_t missingFields, int32_t flags, UErrorCode &status, UDateTimePatternMatchOptions options) {
+ if (U_FAILURE(status)) {
+ return UnicodeString();
+ }
UnicodeString resultPattern, tempPattern;
- const UnicodeString* tempPatternPtr;
+ const UnicodeString* tempPatternPtr;
int32_t lastMissingFieldMask=0;
if (missingFields!=0) {
resultPattern=UnicodeString();
- const PtnSkeleton* specifiedSkeleton=nullptr;
- tempPatternPtr = getBestRaw(*dtMatcher, missingFields, distanceInfo, status, &specifiedSkeleton);
- if (U_FAILURE(status)) {
- return UnicodeString();
- }
- tempPattern = *tempPatternPtr;
+ const PtnSkeleton* specifiedSkeleton=nullptr;
+ tempPatternPtr = getBestRaw(*dtMatcher, missingFields, distanceInfo, status, &specifiedSkeleton);
+ if (U_FAILURE(status)) {
+ return UnicodeString();
+ }
+ tempPattern = *tempPatternPtr;
resultPattern = adjustFieldTypes(tempPattern, specifiedSkeleton, flags, options);
if ( distanceInfo->missingFieldMask==0 ) {
return resultPattern;
@@ -1715,26 +1715,26 @@ DateTimePatternGenerator::getBestAppending(int32_t missingFields, int32_t flags,
continue;
}
int32_t startingMask = distanceInfo->missingFieldMask;
- tempPatternPtr = getBestRaw(*dtMatcher, distanceInfo->missingFieldMask, distanceInfo, status, &specifiedSkeleton);
- if (U_FAILURE(status)) {
- return UnicodeString();
- }
- tempPattern = *tempPatternPtr;
+ tempPatternPtr = getBestRaw(*dtMatcher, distanceInfo->missingFieldMask, distanceInfo, status, &specifiedSkeleton);
+ if (U_FAILURE(status)) {
+ return UnicodeString();
+ }
+ tempPattern = *tempPatternPtr;
tempPattern = adjustFieldTypes(tempPattern, specifiedSkeleton, flags, options);
int32_t foundMask=startingMask& ~distanceInfo->missingFieldMask;
int32_t topField=getTopBitNumber(foundMask);
-
- if (appendItemFormats[topField].length() != 0) {
- UnicodeString appendName;
- getAppendName((UDateTimePatternField)topField, appendName);
- const UnicodeString *values[3] = {
- &resultPattern,
- &tempPattern,
- &appendName
- };
- SimpleFormatter(appendItemFormats[topField], 2, 3, status).
- formatAndReplace(values, 3, resultPattern, nullptr, 0, status);
- }
+
+ if (appendItemFormats[topField].length() != 0) {
+ UnicodeString appendName;
+ getAppendName((UDateTimePatternField)topField, appendName);
+ const UnicodeString *values[3] = {
+ &resultPattern,
+ &tempPattern,
+ &appendName
+ };
+ SimpleFormatter(appendItemFormats[topField], 2, 3, status).
+ formatAndReplace(values, 3, resultPattern, nullptr, 0, status);
+ }
lastMissingFieldMask = distanceInfo->missingFieldMask;
}
}
@@ -1742,7 +1742,7 @@ DateTimePatternGenerator::getBestAppending(int32_t missingFields, int32_t flags,
}
int32_t
-DateTimePatternGenerator::getTopBitNumber(int32_t foundMask) const {
+DateTimePatternGenerator::getTopBitNumber(int32_t foundMask) const {
if ( foundMask==0 ) {
return 0;
}
@@ -1771,21 +1771,21 @@ DateTimePatternGenerator::isAvailableFormatSet(const UnicodeString &key) const {
void
DateTimePatternGenerator::copyHashtable(Hashtable *other, UErrorCode &status) {
- if (other == nullptr || U_FAILURE(status)) {
+ if (other == nullptr || U_FAILURE(status)) {
return;
}
- if (fAvailableFormatKeyHash != nullptr) {
+ if (fAvailableFormatKeyHash != nullptr) {
delete fAvailableFormatKeyHash;
- fAvailableFormatKeyHash = nullptr;
+ fAvailableFormatKeyHash = nullptr;
}
initHashtable(status);
if(U_FAILURE(status)){
return;
}
int32_t pos = UHASH_FIRST;
- const UHashElement* elem = nullptr;
+ const UHashElement* elem = nullptr;
// walk through the hash table and create a deep clone
- while((elem = other->nextElement(pos))!= nullptr){
+ while((elem = other->nextElement(pos))!= nullptr){
const UHashTok otherKeyTok = elem->key;
UnicodeString* otherKey = (UnicodeString*)otherKeyTok.pointer;
fAvailableFormatKeyHash->puti(*otherKey, 1, status);
@@ -1797,17 +1797,17 @@ DateTimePatternGenerator::copyHashtable(Hashtable *other, UErrorCode &status) {
StringEnumeration*
DateTimePatternGenerator::getSkeletons(UErrorCode& status) const {
- if (U_FAILURE(status)) {
- return nullptr;
- }
- if (U_FAILURE(internalErrorCode)) {
- status = internalErrorCode;
- return nullptr;
- }
- LocalPointer<StringEnumeration> skeletonEnumerator(
- new DTSkeletonEnumeration(*patternMap, DT_SKELETON, status), status);
-
- return U_SUCCESS(status) ? skeletonEnumerator.orphan() : nullptr;
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ if (U_FAILURE(internalErrorCode)) {
+ status = internalErrorCode;
+ return nullptr;
+ }
+ LocalPointer<StringEnumeration> skeletonEnumerator(
+ new DTSkeletonEnumeration(*patternMap, DT_SKELETON, status), status);
+
+ return U_SUCCESS(status) ? skeletonEnumerator.orphan() : nullptr;
}
const UnicodeString&
@@ -1818,70 +1818,70 @@ DateTimePatternGenerator::getPatternForSkeleton(const UnicodeString& skeleton) c
return emptyString;
}
curElem = patternMap->getHeader(skeleton.charAt(0));
- while ( curElem != nullptr ) {
+ while ( curElem != nullptr ) {
if ( curElem->skeleton->getSkeleton()==skeleton ) {
return curElem->pattern;
}
- curElem = curElem->next.getAlias();
+ curElem = curElem->next.getAlias();
}
return emptyString;
}
StringEnumeration*
DateTimePatternGenerator::getBaseSkeletons(UErrorCode& status) const {
- if (U_FAILURE(status)) {
- return nullptr;
- }
- if (U_FAILURE(internalErrorCode)) {
- status = internalErrorCode;
- return nullptr;
- }
- LocalPointer<StringEnumeration> baseSkeletonEnumerator(
- new DTSkeletonEnumeration(*patternMap, DT_BASESKELETON, status), status);
-
- return U_SUCCESS(status) ? baseSkeletonEnumerator.orphan() : nullptr;
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ if (U_FAILURE(internalErrorCode)) {
+ status = internalErrorCode;
+ return nullptr;
+ }
+ LocalPointer<StringEnumeration> baseSkeletonEnumerator(
+ new DTSkeletonEnumeration(*patternMap, DT_BASESKELETON, status), status);
+
+ return U_SUCCESS(status) ? baseSkeletonEnumerator.orphan() : nullptr;
}
StringEnumeration*
DateTimePatternGenerator::getRedundants(UErrorCode& status) {
- if (U_FAILURE(status)) { return nullptr; }
- if (U_FAILURE(internalErrorCode)) {
- status = internalErrorCode;
- return nullptr;
- }
- LocalPointer<StringEnumeration> output(new DTRedundantEnumeration(), status);
- if (U_FAILURE(status)) { return nullptr; }
+ if (U_FAILURE(status)) { return nullptr; }
+ if (U_FAILURE(internalErrorCode)) {
+ status = internalErrorCode;
+ return nullptr;
+ }
+ LocalPointer<StringEnumeration> output(new DTRedundantEnumeration(), status);
+ if (U_FAILURE(status)) { return nullptr; }
const UnicodeString *pattern;
- PatternMapIterator it(status);
- if (U_FAILURE(status)) { return nullptr; }
-
+ PatternMapIterator it(status);
+ if (U_FAILURE(status)) { return nullptr; }
+
for (it.set(*patternMap); it.hasNext(); ) {
DateTimeMatcher current = it.next();
pattern = patternMap->getPatternFromSkeleton(*(it.getSkeleton()));
if ( isCanonicalItem(*pattern) ) {
continue;
}
- if ( skipMatcher == nullptr ) {
+ if ( skipMatcher == nullptr ) {
skipMatcher = new DateTimeMatcher(current);
- if (skipMatcher == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
+ if (skipMatcher == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
}
else {
*skipMatcher = current;
}
UnicodeString trial = getBestPattern(current.getPattern(), status);
- if (U_FAILURE(status)) { return nullptr; }
+ if (U_FAILURE(status)) { return nullptr; }
if (trial == *pattern) {
- ((DTRedundantEnumeration *)output.getAlias())->add(*pattern, status);
- if (U_FAILURE(status)) { return nullptr; }
+ ((DTRedundantEnumeration *)output.getAlias())->add(*pattern, status);
+ if (U_FAILURE(status)) { return nullptr; }
}
if (current.equals(skipMatcher)) {
continue;
}
}
- return output.orphan();
+ return output.orphan();
}
UBool
@@ -1905,54 +1905,54 @@ DateTimePatternGenerator::clone() const {
PatternMap::PatternMap() {
for (int32_t i=0; i < MAX_PATTERN_ENTRIES; ++i ) {
- boot[i] = nullptr;
+ boot[i] = nullptr;
}
isDupAllowed = TRUE;
}
void
PatternMap::copyFrom(const PatternMap& other, UErrorCode& status) {
- if (U_FAILURE(status)) {
- return;
- }
+ if (U_FAILURE(status)) {
+ return;
+ }
this->isDupAllowed = other.isDupAllowed;
- for (int32_t bootIndex = 0; bootIndex < MAX_PATTERN_ENTRIES; ++bootIndex) {
- PtnElem *curElem, *otherElem, *prevElem=nullptr;
+ for (int32_t bootIndex = 0; bootIndex < MAX_PATTERN_ENTRIES; ++bootIndex) {
+ PtnElem *curElem, *otherElem, *prevElem=nullptr;
otherElem = other.boot[bootIndex];
- while (otherElem != nullptr) {
- LocalPointer<PtnElem> newElem(new PtnElem(otherElem->basePattern, otherElem->pattern), status);
- if (U_FAILURE(status)) {
- return; // out of memory
- }
- newElem->skeleton.adoptInsteadAndCheckErrorCode(new PtnSkeleton(*(otherElem->skeleton)), status);
- if (U_FAILURE(status)) {
- return; // out of memory
+ while (otherElem != nullptr) {
+ LocalPointer<PtnElem> newElem(new PtnElem(otherElem->basePattern, otherElem->pattern), status);
+ if (U_FAILURE(status)) {
+ return; // out of memory
}
- newElem->skeletonWasSpecified = otherElem->skeletonWasSpecified;
-
- // Release ownership from the LocalPointer of the PtnElem object.
- // The PtnElem will now be owned by either the boot (for the first entry in the linked-list)
- // or owned by the previous PtnElem object in the linked-list.
- curElem = newElem.orphan();
-
- if (this->boot[bootIndex] == nullptr) {
+ newElem->skeleton.adoptInsteadAndCheckErrorCode(new PtnSkeleton(*(otherElem->skeleton)), status);
+ if (U_FAILURE(status)) {
+ return; // out of memory
+ }
+ newElem->skeletonWasSpecified = otherElem->skeletonWasSpecified;
+
+ // Release ownership from the LocalPointer of the PtnElem object.
+ // The PtnElem will now be owned by either the boot (for the first entry in the linked-list)
+ // or owned by the previous PtnElem object in the linked-list.
+ curElem = newElem.orphan();
+
+ if (this->boot[bootIndex] == nullptr) {
this->boot[bootIndex] = curElem;
- } else {
- if (prevElem != nullptr) {
- prevElem->next.adoptInstead(curElem);
- } else {
- UPRV_UNREACHABLE;
- }
+ } else {
+ if (prevElem != nullptr) {
+ prevElem->next.adoptInstead(curElem);
+ } else {
+ UPRV_UNREACHABLE;
+ }
}
prevElem = curElem;
- otherElem = otherElem->next.getAlias();
+ otherElem = otherElem->next.getAlias();
}
}
}
PtnElem*
-PatternMap::getHeader(UChar baseChar) const {
+PatternMap::getHeader(UChar baseChar) const {
PtnElem* curElem;
if ( (baseChar >= CAP_A) && (baseChar <= CAP_Z) ) {
@@ -1963,7 +1963,7 @@ PatternMap::getHeader(UChar baseChar) const {
curElem = boot[26+baseChar-LOW_A];
}
else {
- return nullptr;
+ return nullptr;
}
}
return curElem;
@@ -1971,9 +1971,9 @@ PatternMap::getHeader(UChar baseChar) const {
PatternMap::~PatternMap() {
for (int32_t i=0; i < MAX_PATTERN_ENTRIES; ++i ) {
- if (boot[i] != nullptr ) {
+ if (boot[i] != nullptr ) {
delete boot[i];
- boot[i] = nullptr;
+ boot[i] = nullptr;
}
}
} // PatternMap destructor
@@ -2002,45 +2002,45 @@ PatternMap::add(const UnicodeString& basePattern,
}
}
- if (baseElem == nullptr) {
- LocalPointer<PtnElem> newElem(new PtnElem(basePattern, value), status);
- if (U_FAILURE(status)) {
- return; // out of memory
+ if (baseElem == nullptr) {
+ LocalPointer<PtnElem> newElem(new PtnElem(basePattern, value), status);
+ if (U_FAILURE(status)) {
+ return; // out of memory
}
- newElem->skeleton.adoptInsteadAndCheckErrorCode(new PtnSkeleton(skeleton), status);
- if (U_FAILURE(status)) {
- return; // out of memory
- }
- newElem->skeletonWasSpecified = skeletonWasSpecified;
+ newElem->skeleton.adoptInsteadAndCheckErrorCode(new PtnSkeleton(skeleton), status);
+ if (U_FAILURE(status)) {
+ return; // out of memory
+ }
+ newElem->skeletonWasSpecified = skeletonWasSpecified;
if (baseChar >= LOW_A) {
- boot[26 + (baseChar - LOW_A)] = newElem.orphan(); // the boot array now owns the PtnElem.
+ boot[26 + (baseChar - LOW_A)] = newElem.orphan(); // the boot array now owns the PtnElem.
}
else {
- boot[baseChar - CAP_A] = newElem.orphan(); // the boot array now owns the PtnElem.
+ boot[baseChar - CAP_A] = newElem.orphan(); // the boot array now owns the PtnElem.
}
}
- if ( baseElem != nullptr ) {
+ if ( baseElem != nullptr ) {
curElem = getDuplicateElem(basePattern, skeleton, baseElem);
- if (curElem == nullptr) {
+ if (curElem == nullptr) {
// add new element to the list.
curElem = baseElem;
- while( curElem -> next != nullptr )
+ while( curElem -> next != nullptr )
{
- curElem = curElem->next.getAlias();
- }
-
- LocalPointer<PtnElem> newElem(new PtnElem(basePattern, value), status);
- if (U_FAILURE(status)) {
- return; // out of memory
+ curElem = curElem->next.getAlias();
}
- newElem->skeleton.adoptInsteadAndCheckErrorCode(new PtnSkeleton(skeleton), status);
- if (U_FAILURE(status)) {
- return; // out of memory
+
+ LocalPointer<PtnElem> newElem(new PtnElem(basePattern, value), status);
+ if (U_FAILURE(status)) {
+ return; // out of memory
}
- newElem->skeletonWasSpecified = skeletonWasSpecified;
- curElem->next.adoptInstead(newElem.orphan());
- curElem = curElem->next.getAlias();
+ newElem->skeleton.adoptInsteadAndCheckErrorCode(new PtnSkeleton(skeleton), status);
+ if (U_FAILURE(status)) {
+ return; // out of memory
+ }
+ newElem->skeletonWasSpecified = skeletonWasSpecified;
+ curElem->next.adoptInstead(newElem.orphan());
+ curElem = curElem->next.getAlias();
}
else {
// Pattern exists in the list already.
@@ -2058,11 +2058,11 @@ PatternMap::add(const UnicodeString& basePattern,
// Find the pattern from the given basePattern string.
const UnicodeString *
-PatternMap::getPatternFromBasePattern(const UnicodeString& basePattern, UBool& skeletonWasSpecified) const { // key to search for
+PatternMap::getPatternFromBasePattern(const UnicodeString& basePattern, UBool& skeletonWasSpecified) const { // key to search for
PtnElem *curElem;
- if ((curElem=getHeader(basePattern.charAt(0)))==nullptr) {
- return nullptr; // no match
+ if ((curElem=getHeader(basePattern.charAt(0)))==nullptr) {
+ return nullptr; // no match
}
do {
@@ -2070,10 +2070,10 @@ PatternMap::getPatternFromBasePattern(const UnicodeString& basePattern, UBool& s
skeletonWasSpecified = curElem->skeletonWasSpecified;
return &(curElem->pattern);
}
- curElem = curElem->next.getAlias();
- } while (curElem != nullptr);
+ curElem = curElem->next.getAlias();
+ } while (curElem != nullptr);
- return nullptr;
+ return nullptr;
} // PatternMap::getFromBasePattern
@@ -2084,69 +2084,69 @@ PatternMap::getPatternFromBasePattern(const UnicodeString& basePattern, UBool& s
// optimum distance value in getBestRaw. When this is called from public getRedundants (specifiedSkeletonPtr is NULL),
// for now it will continue to compare based on baseOriginal so as not to change the behavior unnecessarily.
const UnicodeString *
-PatternMap::getPatternFromSkeleton(const PtnSkeleton& skeleton, const PtnSkeleton** specifiedSkeletonPtr) const { // key to search for
+PatternMap::getPatternFromSkeleton(const PtnSkeleton& skeleton, const PtnSkeleton** specifiedSkeletonPtr) const { // key to search for
PtnElem *curElem;
if (specifiedSkeletonPtr) {
- *specifiedSkeletonPtr = nullptr;
+ *specifiedSkeletonPtr = nullptr;
}
// find boot entry
UChar baseChar = skeleton.getFirstChar();
- if ((curElem=getHeader(baseChar))==nullptr) {
- return nullptr; // no match
+ if ((curElem=getHeader(baseChar))==nullptr) {
+ return nullptr; // no match
}
do {
UBool equal;
- if (specifiedSkeletonPtr != nullptr) { // called from DateTimePatternGenerator::getBestRaw or addPattern, use original
+ if (specifiedSkeletonPtr != nullptr) { // called from DateTimePatternGenerator::getBestRaw or addPattern, use original
equal = curElem->skeleton->original == skeleton.original;
} else { // called from DateTimePatternGenerator::getRedundants, use baseOriginal
equal = curElem->skeleton->baseOriginal == skeleton.baseOriginal;
}
if (equal) {
if (specifiedSkeletonPtr && curElem->skeletonWasSpecified) {
- *specifiedSkeletonPtr = curElem->skeleton.getAlias();
+ *specifiedSkeletonPtr = curElem->skeleton.getAlias();
}
return &(curElem->pattern);
}
- curElem = curElem->next.getAlias();
- } while (curElem != nullptr);
+ curElem = curElem->next.getAlias();
+ } while (curElem != nullptr);
- return nullptr;
+ return nullptr;
}
UBool
-PatternMap::equals(const PatternMap& other) const {
+PatternMap::equals(const PatternMap& other) const {
if ( this==&other ) {
return TRUE;
}
- for (int32_t bootIndex = 0; bootIndex < MAX_PATTERN_ENTRIES; ++bootIndex) {
- if (boot[bootIndex] == other.boot[bootIndex]) {
+ for (int32_t bootIndex = 0; bootIndex < MAX_PATTERN_ENTRIES; ++bootIndex) {
+ if (boot[bootIndex] == other.boot[bootIndex]) {
continue;
}
- if ((boot[bootIndex] == nullptr) || (other.boot[bootIndex] == nullptr)) {
+ if ((boot[bootIndex] == nullptr) || (other.boot[bootIndex] == nullptr)) {
return FALSE;
}
PtnElem *otherElem = other.boot[bootIndex];
PtnElem *myElem = boot[bootIndex];
- while ((otherElem != nullptr) || (myElem != nullptr)) {
+ while ((otherElem != nullptr) || (myElem != nullptr)) {
if ( myElem == otherElem ) {
break;
}
- if ((otherElem == nullptr) || (myElem == nullptr)) {
+ if ((otherElem == nullptr) || (myElem == nullptr)) {
return FALSE;
}
if ( (myElem->basePattern != otherElem->basePattern) ||
(myElem->pattern != otherElem->pattern) ) {
return FALSE;
}
- if ((myElem->skeleton.getAlias() != otherElem->skeleton.getAlias()) &&
+ if ((myElem->skeleton.getAlias() != otherElem->skeleton.getAlias()) &&
!myElem->skeleton->equals(*(otherElem->skeleton))) {
return FALSE;
}
- myElem = myElem->next.getAlias();
- otherElem = otherElem->next.getAlias();
+ myElem = myElem->next.getAlias();
+ otherElem = otherElem->next.getAlias();
}
}
return TRUE;
@@ -2158,21 +2158,21 @@ PtnElem*
PatternMap::getDuplicateElem(
const UnicodeString &basePattern,
const PtnSkeleton &skeleton,
- PtnElem *baseElem) {
+ PtnElem *baseElem) {
PtnElem *curElem;
- if ( baseElem == nullptr ) {
- return nullptr;
+ if ( baseElem == nullptr ) {
+ return nullptr;
}
else {
curElem = baseElem;
}
do {
if ( basePattern.compare(curElem->basePattern)==0 ) {
- UBool isEqual = TRUE;
- for (int32_t i = 0; i < UDATPG_FIELD_COUNT; ++i) {
+ UBool isEqual = TRUE;
+ for (int32_t i = 0; i < UDATPG_FIELD_COUNT; ++i) {
if (curElem->skeleton->type[i] != skeleton.type[i] ) {
- isEqual = FALSE;
+ isEqual = FALSE;
break;
}
}
@@ -2180,11 +2180,11 @@ PatternMap::getDuplicateElem(
return curElem;
}
}
- curElem = curElem->next.getAlias();
- } while( curElem != nullptr );
+ curElem = curElem->next.getAlias();
+ } while( curElem != nullptr );
// end of the list
- return nullptr;
+ return nullptr;
} // PatternMap::getDuplicateElem
@@ -2197,12 +2197,12 @@ DateTimeMatcher::DateTimeMatcher(const DateTimeMatcher& other) {
copyFrom(other.skeleton);
}
-DateTimeMatcher& DateTimeMatcher::operator=(const DateTimeMatcher& other) {
- copyFrom(other.skeleton);
- return *this;
-}
-
+DateTimeMatcher& DateTimeMatcher::operator=(const DateTimeMatcher& other) {
+ copyFrom(other.skeleton);
+ return *this;
+}
+
void
DateTimeMatcher::set(const UnicodeString& pattern, FormatParser* fp) {
PtnSkeleton localSkeleton;
@@ -2215,14 +2215,14 @@ DateTimeMatcher::set(const UnicodeString& pattern, FormatParser* fp, PtnSkeleton
for (i=0; i<UDATPG_FIELD_COUNT; ++i) {
skeletonResult.type[i] = NONE;
}
- skeletonResult.original.clear();
- skeletonResult.baseOriginal.clear();
- skeletonResult.addedDefaultDayPeriod = FALSE;
-
+ skeletonResult.original.clear();
+ skeletonResult.baseOriginal.clear();
+ skeletonResult.addedDefaultDayPeriod = FALSE;
+
fp->set(pattern);
for (i=0; i < fp->itemNumber; i++) {
const UnicodeString& value = fp->items[i];
- // don't skip 'a' anymore, dayPeriod handled specially below
+ // don't skip 'a' anymore, dayPeriod handled specially below
if ( fp->isQuoteLiteral(value) ) {
UnicodeString quoteLiteral;
@@ -2230,73 +2230,73 @@ DateTimeMatcher::set(const UnicodeString& pattern, FormatParser* fp, PtnSkeleton
continue;
}
int32_t canonicalIndex = fp->getCanonicalIndex(value);
- if (canonicalIndex < 0) {
+ if (canonicalIndex < 0) {
continue;
}
const dtTypeElem *row = &dtTypes[canonicalIndex];
int32_t field = row->field;
skeletonResult.original.populate(field, value);
UChar repeatChar = row->patternChar;
- int32_t repeatCount = row->minLen;
+ int32_t repeatCount = row->minLen;
skeletonResult.baseOriginal.populate(field, repeatChar, repeatCount);
int16_t subField = row->type;
- if (row->type > 0) {
- U_ASSERT(value.length() < INT16_MAX);
- subField += static_cast<int16_t>(value.length());
+ if (row->type > 0) {
+ U_ASSERT(value.length() < INT16_MAX);
+ subField += static_cast<int16_t>(value.length());
}
skeletonResult.type[field] = subField;
}
-
- // #20739, we have a skeleton with minutes and milliseconds, but no seconds
- //
- // Theoretically we would need to check and fix all fields with "gaps":
- // for example year-day (no month), month-hour (no day), and so on, All the possible field combinations.
- // Plus some smartness: year + hour => should we add month, or add day-of-year?
- // What about month + day-of-week, or month + am/pm indicator.
- // I think beyond a certain point we should not try to fix bad developer input and try guessing what they mean.
- // Garbage in, garbage out.
- if (!skeletonResult.original.isFieldEmpty(UDATPG_MINUTE_FIELD)
- && !skeletonResult.original.isFieldEmpty(UDATPG_FRACTIONAL_SECOND_FIELD)
- && skeletonResult.original.isFieldEmpty(UDATPG_SECOND_FIELD)) {
- // Force the use of seconds
- for (i = 0; dtTypes[i].patternChar != 0; i++) {
- if (dtTypes[i].field == UDATPG_SECOND_FIELD) {
- // first entry for UDATPG_SECOND_FIELD
- skeletonResult.original.populate(UDATPG_SECOND_FIELD, dtTypes[i].patternChar, dtTypes[i].minLen);
- skeletonResult.baseOriginal.populate(UDATPG_SECOND_FIELD, dtTypes[i].patternChar, dtTypes[i].minLen);
- // We add value.length, same as above, when type is first initialized.
- // The value we want to "fake" here is "s", and 1 means "s".length()
- int16_t subField = dtTypes[i].type;
- skeletonResult.type[UDATPG_SECOND_FIELD] = (subField > 0) ? subField + 1 : subField;
- break;
- }
- }
- }
-
- // #13183, handle special behavior for day period characters (a, b, B)
- if (!skeletonResult.original.isFieldEmpty(UDATPG_HOUR_FIELD)) {
- if (skeletonResult.original.getFieldChar(UDATPG_HOUR_FIELD)==LOW_H || skeletonResult.original.getFieldChar(UDATPG_HOUR_FIELD)==CAP_K) {
- // We have a skeleton with 12-hour-cycle format
- if (skeletonResult.original.isFieldEmpty(UDATPG_DAYPERIOD_FIELD)) {
- // But we do not have a day period in the skeleton; add the default DAYPERIOD (currently "a")
- for (i = 0; dtTypes[i].patternChar != 0; i++) {
- if ( dtTypes[i].field == UDATPG_DAYPERIOD_FIELD ) {
- // first entry for UDATPG_DAYPERIOD_FIELD
- skeletonResult.original.populate(UDATPG_DAYPERIOD_FIELD, dtTypes[i].patternChar, dtTypes[i].minLen);
- skeletonResult.baseOriginal.populate(UDATPG_DAYPERIOD_FIELD, dtTypes[i].patternChar, dtTypes[i].minLen);
- skeletonResult.type[UDATPG_DAYPERIOD_FIELD] = dtTypes[i].type;
- skeletonResult.addedDefaultDayPeriod = TRUE;
- break;
- }
- }
- }
- } else {
- // Skeleton has 24-hour-cycle hour format and has dayPeriod, delete dayPeriod (i.e. ignore it)
- skeletonResult.original.clearField(UDATPG_DAYPERIOD_FIELD);
- skeletonResult.baseOriginal.clearField(UDATPG_DAYPERIOD_FIELD);
- skeletonResult.type[UDATPG_DAYPERIOD_FIELD] = NONE;
- }
- }
+
+ // #20739, we have a skeleton with minutes and milliseconds, but no seconds
+ //
+ // Theoretically we would need to check and fix all fields with "gaps":
+ // for example year-day (no month), month-hour (no day), and so on, All the possible field combinations.
+ // Plus some smartness: year + hour => should we add month, or add day-of-year?
+ // What about month + day-of-week, or month + am/pm indicator.
+ // I think beyond a certain point we should not try to fix bad developer input and try guessing what they mean.
+ // Garbage in, garbage out.
+ if (!skeletonResult.original.isFieldEmpty(UDATPG_MINUTE_FIELD)
+ && !skeletonResult.original.isFieldEmpty(UDATPG_FRACTIONAL_SECOND_FIELD)
+ && skeletonResult.original.isFieldEmpty(UDATPG_SECOND_FIELD)) {
+ // Force the use of seconds
+ for (i = 0; dtTypes[i].patternChar != 0; i++) {
+ if (dtTypes[i].field == UDATPG_SECOND_FIELD) {
+ // first entry for UDATPG_SECOND_FIELD
+ skeletonResult.original.populate(UDATPG_SECOND_FIELD, dtTypes[i].patternChar, dtTypes[i].minLen);
+ skeletonResult.baseOriginal.populate(UDATPG_SECOND_FIELD, dtTypes[i].patternChar, dtTypes[i].minLen);
+ // We add value.length, same as above, when type is first initialized.
+ // The value we want to "fake" here is "s", and 1 means "s".length()
+ int16_t subField = dtTypes[i].type;
+ skeletonResult.type[UDATPG_SECOND_FIELD] = (subField > 0) ? subField + 1 : subField;
+ break;
+ }
+ }
+ }
+
+ // #13183, handle special behavior for day period characters (a, b, B)
+ if (!skeletonResult.original.isFieldEmpty(UDATPG_HOUR_FIELD)) {
+ if (skeletonResult.original.getFieldChar(UDATPG_HOUR_FIELD)==LOW_H || skeletonResult.original.getFieldChar(UDATPG_HOUR_FIELD)==CAP_K) {
+ // We have a skeleton with 12-hour-cycle format
+ if (skeletonResult.original.isFieldEmpty(UDATPG_DAYPERIOD_FIELD)) {
+ // But we do not have a day period in the skeleton; add the default DAYPERIOD (currently "a")
+ for (i = 0; dtTypes[i].patternChar != 0; i++) {
+ if ( dtTypes[i].field == UDATPG_DAYPERIOD_FIELD ) {
+ // first entry for UDATPG_DAYPERIOD_FIELD
+ skeletonResult.original.populate(UDATPG_DAYPERIOD_FIELD, dtTypes[i].patternChar, dtTypes[i].minLen);
+ skeletonResult.baseOriginal.populate(UDATPG_DAYPERIOD_FIELD, dtTypes[i].patternChar, dtTypes[i].minLen);
+ skeletonResult.type[UDATPG_DAYPERIOD_FIELD] = dtTypes[i].type;
+ skeletonResult.addedDefaultDayPeriod = TRUE;
+ break;
+ }
+ }
+ }
+ } else {
+ // Skeleton has 24-hour-cycle hour format and has dayPeriod, delete dayPeriod (i.e. ignore it)
+ skeletonResult.original.clearField(UDATPG_DAYPERIOD_FIELD);
+ skeletonResult.baseOriginal.clearField(UDATPG_DAYPERIOD_FIELD);
+ skeletonResult.type[UDATPG_DAYPERIOD_FIELD] = NONE;
+ }
+ }
copyFrom(skeletonResult);
}
@@ -2313,8 +2313,8 @@ DateTimeMatcher::getPattern() {
}
int32_t
-DateTimeMatcher::getDistance(const DateTimeMatcher& other, int32_t includeMask, DistanceInfo& distanceInfo) const {
- int32_t result = 0;
+DateTimeMatcher::getDistance(const DateTimeMatcher& other, int32_t includeMask, DistanceInfo& distanceInfo) const {
+ int32_t result = 0;
distanceInfo.clear();
for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) {
int32_t myType = (includeMask&(1<<i))==0 ? 0 : skeleton.type[i];
@@ -2353,13 +2353,13 @@ DateTimeMatcher::copyFrom() {
UBool
DateTimeMatcher::equals(const DateTimeMatcher* other) const {
- if (other==nullptr) { return FALSE; }
+ if (other==nullptr) { return FALSE; }
return skeleton.original == other->skeleton.original;
}
int32_t
-DateTimeMatcher::getFieldMask() const {
- int32_t result = 0;
+DateTimeMatcher::getFieldMask() const {
+ int32_t result = 0;
for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
if (skeleton.type[i]!=0) {
@@ -2376,7 +2376,7 @@ DateTimeMatcher::getSkeletonPtr() {
FormatParser::FormatParser () {
status = START;
- itemNumber = 0;
+ itemNumber = 0;
}
@@ -2388,7 +2388,7 @@ FormatParser::~FormatParser () {
// Note: the startPos may
FormatParser::TokenStatus
FormatParser::setTokens(const UnicodeString& pattern, int32_t startPos, int32_t *len) {
- int32_t curLoc = startPos;
+ int32_t curLoc = startPos;
if ( curLoc >= pattern.length()) {
return DONE;
}
@@ -2414,10 +2414,10 @@ FormatParser::setTokens(const UnicodeString& pattern, int32_t startPos, int32_t
void
FormatParser::set(const UnicodeString& pattern) {
- int32_t startPos = 0;
- TokenStatus result = START;
- int32_t len = 0;
- itemNumber = 0;
+ int32_t startPos = 0;
+ TokenStatus result = START;
+ int32_t len = 0;
+ itemNumber = 0;
do {
result = setTokens( pattern, startPos, &len );
@@ -2468,14 +2468,14 @@ FormatParser::getCanonicalIndex(const UnicodeString& s, UBool strict) {
UBool
FormatParser::isQuoteLiteral(const UnicodeString& s) {
- return (UBool)(s.charAt(0) == SINGLE_QUOTE);
+ return (UBool)(s.charAt(0) == SINGLE_QUOTE);
}
-// This function assumes the current itemIndex points to the quote literal.
+// This function assumes the current itemIndex points to the quote literal.
// Please call isQuoteLiteral prior to this function.
void
FormatParser::getQuoteLiteral(UnicodeString& quote, int32_t *itemIndex) {
- int32_t i = *itemIndex;
+ int32_t i = *itemIndex;
quote.remove();
if (items[i].charAt(0)==SINGLE_QUOTE) {
@@ -2504,7 +2504,7 @@ FormatParser::getQuoteLiteral(UnicodeString& quote, int32_t *itemIndex) {
}
UBool
-FormatParser::isPatternSeparator(const UnicodeString& field) const {
+FormatParser::isPatternSeparator(const UnicodeString& field) const {
for (int32_t i=0; i<field.length(); ++i ) {
UChar c= field.charAt(i);
if ( (c==SINGLE_QUOTE) || (c==BACKSLASH) || (c==SPACE) || (c==COLON) ||
@@ -2521,16 +2521,16 @@ FormatParser::isPatternSeparator(const UnicodeString& field) const {
DistanceInfo::~DistanceInfo() {}
void
-DistanceInfo::setTo(const DistanceInfo& other) {
+DistanceInfo::setTo(const DistanceInfo& other) {
missingFieldMask = other.missingFieldMask;
extraFieldMask= other.extraFieldMask;
}
-PatternMapIterator::PatternMapIterator(UErrorCode& status) :
- bootIndex(0), nodePtr(nullptr), matcher(nullptr), patternMap(nullptr)
-{
- if (U_FAILURE(status)) { return; }
- matcher.adoptInsteadAndCheckErrorCode(new DateTimeMatcher(), status);
+PatternMapIterator::PatternMapIterator(UErrorCode& status) :
+ bootIndex(0), nodePtr(nullptr), matcher(nullptr), patternMap(nullptr)
+{
+ if (U_FAILURE(status)) { return; }
+ matcher.adoptInsteadAndCheckErrorCode(new DateTimeMatcher(), status);
}
PatternMapIterator::~PatternMapIterator() {
@@ -2542,36 +2542,36 @@ PatternMapIterator::set(PatternMap& newPatternMap) {
}
PtnSkeleton*
-PatternMapIterator::getSkeleton() const {
- if ( nodePtr == nullptr ) {
- return nullptr;
+PatternMapIterator::getSkeleton() const {
+ if ( nodePtr == nullptr ) {
+ return nullptr;
}
else {
- return nodePtr->skeleton.getAlias();
+ return nodePtr->skeleton.getAlias();
}
}
UBool
-PatternMapIterator::hasNext() const {
- int32_t headIndex = bootIndex;
- PtnElem *curPtr = nodePtr;
+PatternMapIterator::hasNext() const {
+ int32_t headIndex = bootIndex;
+ PtnElem *curPtr = nodePtr;
- if (patternMap==nullptr) {
+ if (patternMap==nullptr) {
return FALSE;
}
while ( headIndex < MAX_PATTERN_ENTRIES ) {
- if ( curPtr != nullptr ) {
- if ( curPtr->next != nullptr ) {
+ if ( curPtr != nullptr ) {
+ if ( curPtr->next != nullptr ) {
return TRUE;
}
else {
headIndex++;
- curPtr=nullptr;
+ curPtr=nullptr;
continue;
}
}
else {
- if ( patternMap->boot[headIndex] != nullptr ) {
+ if ( patternMap->boot[headIndex] != nullptr ) {
return TRUE;
}
else {
@@ -2586,19 +2586,19 @@ PatternMapIterator::hasNext() const {
DateTimeMatcher&
PatternMapIterator::next() {
while ( bootIndex < MAX_PATTERN_ENTRIES ) {
- if ( nodePtr != nullptr ) {
- if ( nodePtr->next != nullptr ) {
- nodePtr = nodePtr->next.getAlias();
+ if ( nodePtr != nullptr ) {
+ if ( nodePtr->next != nullptr ) {
+ nodePtr = nodePtr->next.getAlias();
break;
}
else {
bootIndex++;
- nodePtr=nullptr;
+ nodePtr=nullptr;
continue;
}
}
else {
- if ( patternMap->boot[bootIndex] != nullptr ) {
+ if ( patternMap->boot[bootIndex] != nullptr ) {
nodePtr = patternMap->boot[bootIndex];
break;
}
@@ -2608,7 +2608,7 @@ PatternMapIterator::next() {
}
}
}
- if (nodePtr!=nullptr) {
+ if (nodePtr!=nullptr) {
matcher->copyFrom(*nodePtr->skeleton);
}
else {
@@ -2686,8 +2686,8 @@ UChar SkeletonFields::getFirstChar() const {
}
-PtnSkeleton::PtnSkeleton()
- : addedDefaultDayPeriod(FALSE) {
+PtnSkeleton::PtnSkeleton()
+ : addedDefaultDayPeriod(FALSE) {
}
PtnSkeleton::PtnSkeleton(const PtnSkeleton& other) {
@@ -2698,7 +2698,7 @@ void PtnSkeleton::copyFrom(const PtnSkeleton& other) {
uprv_memcpy(type, other.type, sizeof(type));
original.copyFrom(other.original);
baseOriginal.copyFrom(other.baseOriginal);
- addedDefaultDayPeriod = other.addedDefaultDayPeriod;
+ addedDefaultDayPeriod = other.addedDefaultDayPeriod;
}
void PtnSkeleton::clear() {
@@ -2717,27 +2717,27 @@ PtnSkeleton::equals(const PtnSkeleton& other) const {
UnicodeString
PtnSkeleton::getSkeleton() const {
UnicodeString result;
- result = original.appendTo(result);
- int32_t pos;
- if (addedDefaultDayPeriod && (pos = result.indexOf(LOW_A)) >= 0) {
- // for backward compatibility: if DateTimeMatcher.set added a single 'a' that
- // was not in the provided skeleton, remove it here before returning skeleton.
- result.remove(pos, 1);
- }
- return result;
+ result = original.appendTo(result);
+ int32_t pos;
+ if (addedDefaultDayPeriod && (pos = result.indexOf(LOW_A)) >= 0) {
+ // for backward compatibility: if DateTimeMatcher.set added a single 'a' that
+ // was not in the provided skeleton, remove it here before returning skeleton.
+ result.remove(pos, 1);
+ }
+ return result;
}
UnicodeString
PtnSkeleton::getBaseSkeleton() const {
UnicodeString result;
- result = baseOriginal.appendTo(result);
- int32_t pos;
- if (addedDefaultDayPeriod && (pos = result.indexOf(LOW_A)) >= 0) {
- // for backward compatibility: if DateTimeMatcher.set added a single 'a' that
- // was not in the provided skeleton, remove it here before returning skeleton.
- result.remove(pos, 1);
- }
- return result;
+ result = baseOriginal.appendTo(result);
+ int32_t pos;
+ if (addedDefaultDayPeriod && (pos = result.indexOf(LOW_A)) >= 0) {
+ // for backward compatibility: if DateTimeMatcher.set added a single 'a' that
+ // was not in the provided skeleton, remove it here before returning skeleton.
+ result.remove(pos, 1);
+ }
+ return result;
}
UChar
@@ -2749,28 +2749,28 @@ PtnSkeleton::~PtnSkeleton() {
}
PtnElem::PtnElem(const UnicodeString &basePat, const UnicodeString &pat) :
- basePattern(basePat), skeleton(nullptr), pattern(pat), next(nullptr)
+ basePattern(basePat), skeleton(nullptr), pattern(pat), next(nullptr)
{
}
PtnElem::~PtnElem() {
}
-DTSkeletonEnumeration::DTSkeletonEnumeration(PatternMap& patternMap, dtStrEnum type, UErrorCode& status) : fSkeletons(nullptr) {
+DTSkeletonEnumeration::DTSkeletonEnumeration(PatternMap& patternMap, dtStrEnum type, UErrorCode& status) : fSkeletons(nullptr) {
PtnElem *curElem;
PtnSkeleton *curSkeleton;
UnicodeString s;
int32_t bootIndex;
pos=0;
- fSkeletons.adoptInsteadAndCheckErrorCode(new UVector(status), status);
+ fSkeletons.adoptInsteadAndCheckErrorCode(new UVector(status), status);
if (U_FAILURE(status)) {
return;
}
-
+
for (bootIndex=0; bootIndex<MAX_PATTERN_ENTRIES; ++bootIndex ) {
curElem = patternMap.boot[bootIndex];
- while (curElem!=nullptr) {
+ while (curElem!=nullptr) {
switch(type) {
case DT_BASESKELETON:
s=curElem->basePattern;
@@ -2779,36 +2779,36 @@ DTSkeletonEnumeration::DTSkeletonEnumeration(PatternMap& patternMap, dtStrEnum t
s=curElem->pattern;
break;
case DT_SKELETON:
- curSkeleton=curElem->skeleton.getAlias();
+ curSkeleton=curElem->skeleton.getAlias();
s=curSkeleton->getSkeleton();
break;
}
if ( !isCanonicalItem(s) ) {
- LocalPointer<UnicodeString> newElem(new UnicodeString(s), status);
- if (U_FAILURE(status)) {
- return;
- }
- fSkeletons->addElement(newElem.getAlias(), status);
+ LocalPointer<UnicodeString> newElem(new UnicodeString(s), status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fSkeletons->addElement(newElem.getAlias(), status);
if (U_FAILURE(status)) {
- fSkeletons.adoptInstead(nullptr);
+ fSkeletons.adoptInstead(nullptr);
return;
}
- newElem.orphan(); // fSkeletons vector now owns the UnicodeString.
+ newElem.orphan(); // fSkeletons vector now owns the UnicodeString.
}
- curElem = curElem->next.getAlias();
+ curElem = curElem->next.getAlias();
}
}
- if ((bootIndex==MAX_PATTERN_ENTRIES) && (curElem!=nullptr) ) {
+ if ((bootIndex==MAX_PATTERN_ENTRIES) && (curElem!=nullptr) ) {
status = U_BUFFER_OVERFLOW_ERROR;
}
}
const UnicodeString*
DTSkeletonEnumeration::snext(UErrorCode& status) {
- if (U_SUCCESS(status) && fSkeletons.isValid() && pos < fSkeletons->size()) {
+ if (U_SUCCESS(status) && fSkeletons.isValid() && pos < fSkeletons->size()) {
return (const UnicodeString*)fSkeletons->elementAt(pos++);
}
- return nullptr;
+ return nullptr;
}
void
@@ -2818,7 +2818,7 @@ DTSkeletonEnumeration::reset(UErrorCode& /*status*/) {
int32_t
DTSkeletonEnumeration::count(UErrorCode& /*status*/) const {
- return (fSkeletons.isNull()) ? 0 : fSkeletons->size();
+ return (fSkeletons.isNull()) ? 0 : fSkeletons->size();
}
UBool
@@ -2836,45 +2836,45 @@ DTSkeletonEnumeration::isCanonicalItem(const UnicodeString& item) {
DTSkeletonEnumeration::~DTSkeletonEnumeration() {
UnicodeString *s;
- if (fSkeletons.isValid()) {
- for (int32_t i = 0; i < fSkeletons->size(); ++i) {
- if ((s = (UnicodeString *)fSkeletons->elementAt(i)) != nullptr) {
- delete s;
- }
+ if (fSkeletons.isValid()) {
+ for (int32_t i = 0; i < fSkeletons->size(); ++i) {
+ if ((s = (UnicodeString *)fSkeletons->elementAt(i)) != nullptr) {
+ delete s;
+ }
}
}
}
-DTRedundantEnumeration::DTRedundantEnumeration() : pos(0), fPatterns(nullptr) {
+DTRedundantEnumeration::DTRedundantEnumeration() : pos(0), fPatterns(nullptr) {
}
void
DTRedundantEnumeration::add(const UnicodeString& pattern, UErrorCode& status) {
- if (U_FAILURE(status)) { return; }
- if (fPatterns.isNull()) {
- fPatterns.adoptInsteadAndCheckErrorCode(new UVector(status), status);
+ if (U_FAILURE(status)) { return; }
+ if (fPatterns.isNull()) {
+ fPatterns.adoptInsteadAndCheckErrorCode(new UVector(status), status);
if (U_FAILURE(status)) {
return;
}
}
- LocalPointer<UnicodeString> newElem(new UnicodeString(pattern), status);
+ LocalPointer<UnicodeString> newElem(new UnicodeString(pattern), status);
if (U_FAILURE(status)) {
return;
}
- fPatterns->addElement(newElem.getAlias(), status);
- if (U_FAILURE(status)) {
- fPatterns.adoptInstead(nullptr);
- return;
- }
- newElem.orphan(); // fPatterns now owns the string.
+ fPatterns->addElement(newElem.getAlias(), status);
+ if (U_FAILURE(status)) {
+ fPatterns.adoptInstead(nullptr);
+ return;
+ }
+ newElem.orphan(); // fPatterns now owns the string.
}
const UnicodeString*
DTRedundantEnumeration::snext(UErrorCode& status) {
- if (U_SUCCESS(status) && fPatterns.isValid() && pos < fPatterns->size()) {
+ if (U_SUCCESS(status) && fPatterns.isValid() && pos < fPatterns->size()) {
return (const UnicodeString*)fPatterns->elementAt(pos++);
}
- return nullptr;
+ return nullptr;
}
void
@@ -2884,11 +2884,11 @@ DTRedundantEnumeration::reset(UErrorCode& /*status*/) {
int32_t
DTRedundantEnumeration::count(UErrorCode& /*status*/) const {
- return (fPatterns.isNull()) ? 0 : fPatterns->size();
+ return (fPatterns.isNull()) ? 0 : fPatterns->size();
}
UBool
-DTRedundantEnumeration::isCanonicalItem(const UnicodeString& item) const {
+DTRedundantEnumeration::isCanonicalItem(const UnicodeString& item) const {
if ( item.length() != 1 ) {
return FALSE;
}
@@ -2902,13 +2902,13 @@ DTRedundantEnumeration::isCanonicalItem(const UnicodeString& item) const {
DTRedundantEnumeration::~DTRedundantEnumeration() {
UnicodeString *s;
- if (fPatterns.isValid()) {
- for (int32_t i = 0; i < fPatterns->size(); ++i) {
- if ((s = (UnicodeString *)fPatterns->elementAt(i)) != nullptr) {
- delete s;
- }
+ if (fPatterns.isValid()) {
+ for (int32_t i = 0; i < fPatterns->size(); ++i) {
+ if ((s = (UnicodeString *)fPatterns->elementAt(i)) != nullptr) {
+ delete s;
+ }
}
- }
+ }
}
U_NAMESPACE_END
diff --git a/contrib/libs/icu/i18n/dtptngen_impl.h b/contrib/libs/icu/i18n/dtptngen_impl.h
index ade9f57331..ff0fe133fa 100644
--- a/contrib/libs/icu/i18n/dtptngen_impl.h
+++ b/contrib/libs/icu/i18n/dtptngen_impl.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -15,9 +15,9 @@
#define __DTPTNGEN_IMPL_H__
#include "unicode/udatpg.h"
-
-#include "unicode/strenum.h"
-#include "unicode/unistr.h"
+
+#include "unicode/strenum.h"
+#include "unicode/unistr.h"
#include "uvector.h"
// TODO(claireho): Split off Builder class.
@@ -92,10 +92,10 @@
#define LOW_X ((UChar)0x0078)
#define LOW_Y ((UChar)0x0079)
#define LOW_Z ((UChar)0x007A)
-#define DT_NARROW -0x101
-#define DT_SHORTER -0x102
-#define DT_SHORT -0x103
-#define DT_LONG -0x104
+#define DT_NARROW -0x101
+#define DT_SHORTER -0x102
+#define DT_SHORT -0x103
+#define DT_LONG -0x104
#define DT_NUMERIC 0x100
#define DT_DELTA 0x10
@@ -116,7 +116,7 @@ typedef struct dtTypeElem {
int16_t type;
int16_t minLen;
int16_t weight;
-} dtTypeElem;
+} dtTypeElem;
// A compact storage mechanism for skeleton field strings. Several dozen of these will be created
// for a typical DateTimePatternGenerator instance.
@@ -156,7 +156,7 @@ public:
int32_t type[UDATPG_FIELD_COUNT];
SkeletonFields original;
SkeletonFields baseOriginal;
- UBool addedDefaultDayPeriod;
+ UBool addedDefaultDayPeriod;
PtnSkeleton();
PtnSkeleton(const PtnSkeleton& other);
@@ -175,10 +175,10 @@ public:
class PtnElem : public UMemory {
public:
UnicodeString basePattern;
- LocalPointer<PtnSkeleton> skeleton;
+ LocalPointer<PtnSkeleton> skeleton;
UnicodeString pattern;
UBool skeletonWasSpecified; // if specified in availableFormats, not derived
- LocalPointer<PtnElem> next;
+ LocalPointer<PtnElem> next;
PtnElem(const UnicodeString &basePattern, const UnicodeString &pattern);
virtual ~PtnElem();
@@ -187,13 +187,13 @@ public:
class FormatParser : public UMemory {
public:
UnicodeString items[MAX_DT_TOKEN];
- int32_t itemNumber;
+ int32_t itemNumber;
FormatParser();
virtual ~FormatParser();
void set(const UnicodeString& patternString);
void getQuoteLiteral(UnicodeString& quote, int32_t *itemIndex);
- UBool isPatternSeparator(const UnicodeString& field) const;
+ UBool isPatternSeparator(const UnicodeString& field) const;
static UBool isQuoteLiteral(const UnicodeString& s);
static int32_t getCanonicalIndex(const UnicodeString& s) { return getCanonicalIndex(s, TRUE); }
static int32_t getCanonicalIndex(const UnicodeString& s, UBool strict);
@@ -204,7 +204,7 @@ private:
ADD_TOKEN,
SYNTAX_ERROR,
DONE
- } TokenStatus;
+ } TokenStatus;
TokenStatus status;
virtual TokenStatus setTokens(const UnicodeString& pattern, int32_t startPos, int32_t *len);
@@ -218,7 +218,7 @@ public:
DistanceInfo() {}
virtual ~DistanceInfo();
void clear() { missingFieldMask = extraFieldMask = 0; }
- void setTo(const DistanceInfo& other);
+ void setTo(const DistanceInfo& other);
void addMissing(int32_t field) { missingFieldMask |= (1<<field); }
void addExtra(int32_t field) { extraFieldMask |= (1<<field); }
};
@@ -235,12 +235,12 @@ public:
void copyFrom();
PtnSkeleton* getSkeletonPtr();
UBool equals(const DateTimeMatcher* other) const;
- int32_t getDistance(const DateTimeMatcher& other, int32_t includeMask, DistanceInfo& distanceInfo) const;
+ int32_t getDistance(const DateTimeMatcher& other, int32_t includeMask, DistanceInfo& distanceInfo) const;
DateTimeMatcher();
DateTimeMatcher(const DateTimeMatcher& other);
- DateTimeMatcher& operator=(const DateTimeMatcher& other);
+ DateTimeMatcher& operator=(const DateTimeMatcher& other);
virtual ~DateTimeMatcher();
- int32_t getFieldMask() const;
+ int32_t getFieldMask() const;
};
class PatternMap : public UMemory {
@@ -249,34 +249,34 @@ public:
PatternMap();
virtual ~PatternMap();
void add(const UnicodeString& basePattern, const PtnSkeleton& skeleton, const UnicodeString& value, UBool skeletonWasSpecified, UErrorCode& status);
- const UnicodeString* getPatternFromBasePattern(const UnicodeString& basePattern, UBool& skeletonWasSpecified) const;
- const UnicodeString* getPatternFromSkeleton(const PtnSkeleton& skeleton, const PtnSkeleton** specifiedSkeletonPtr = 0) const;
+ const UnicodeString* getPatternFromBasePattern(const UnicodeString& basePattern, UBool& skeletonWasSpecified) const;
+ const UnicodeString* getPatternFromSkeleton(const PtnSkeleton& skeleton, const PtnSkeleton** specifiedSkeletonPtr = 0) const;
void copyFrom(const PatternMap& other, UErrorCode& status);
- PtnElem* getHeader(UChar baseChar) const;
- UBool equals(const PatternMap& other) const;
+ PtnElem* getHeader(UChar baseChar) const;
+ UBool equals(const PatternMap& other) const;
private:
UBool isDupAllowed;
- PtnElem* getDuplicateElem(const UnicodeString& basePattern, const PtnSkeleton& skeleton, PtnElem *baseElem);
+ PtnElem* getDuplicateElem(const UnicodeString& basePattern, const PtnSkeleton& skeleton, PtnElem *baseElem);
}; // end PatternMap
class PatternMapIterator : public UMemory {
public:
- PatternMapIterator(UErrorCode &status);
+ PatternMapIterator(UErrorCode &status);
virtual ~PatternMapIterator();
void set(PatternMap& patternMap);
- PtnSkeleton* getSkeleton() const;
- UBool hasNext() const;
+ PtnSkeleton* getSkeleton() const;
+ UBool hasNext() const;
DateTimeMatcher& next();
private:
int32_t bootIndex;
PtnElem *nodePtr;
- LocalPointer<DateTimeMatcher> matcher;
+ LocalPointer<DateTimeMatcher> matcher;
PatternMap *patternMap;
};
class DTSkeletonEnumeration : public StringEnumeration {
public:
- DTSkeletonEnumeration(PatternMap& patternMap, dtStrEnum type, UErrorCode& status);
+ DTSkeletonEnumeration(PatternMap& patternMap, dtStrEnum type, UErrorCode& status);
virtual ~DTSkeletonEnumeration();
static UClassID U_EXPORT2 getStaticClassID(void);
virtual UClassID getDynamicClassID(void) const;
@@ -286,7 +286,7 @@ public:
private:
int32_t pos;
UBool isCanonicalItem(const UnicodeString& item);
- LocalPointer<UVector> fSkeletons;
+ LocalPointer<UVector> fSkeletons;
};
class DTRedundantEnumeration : public StringEnumeration {
@@ -301,8 +301,8 @@ public:
void add(const UnicodeString &pattern, UErrorCode& status);
private:
int32_t pos;
- UBool isCanonicalItem(const UnicodeString& item) const;
- LocalPointer<UVector> fPatterns;
+ UBool isCanonicalItem(const UnicodeString& item) const;
+ LocalPointer<UVector> fPatterns;
};
U_NAMESPACE_END
diff --git a/contrib/libs/icu/i18n/dtrule.cpp b/contrib/libs/icu/i18n/dtrule.cpp
index 6847f1d16e..d66fe744d6 100644
--- a/contrib/libs/icu/i18n/dtrule.cpp
+++ b/contrib/libs/icu/i18n/dtrule.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/erarules.cpp b/contrib/libs/icu/i18n/erarules.cpp
index e375740bd6..9f23925958 100644
--- a/contrib/libs/icu/i18n/erarules.cpp
+++ b/contrib/libs/icu/i18n/erarules.cpp
@@ -1,326 +1,326 @@
-// © 2018 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html
-
-#include <utility>
-
-#include "unicode/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include <stdlib.h>
-#include "unicode/ucal.h"
-#include "unicode/ures.h"
-#include "unicode/ustring.h"
-#include "unicode/timezone.h"
-#include "cmemory.h"
-#include "cstring.h"
-#include "erarules.h"
-#include "gregoimp.h"
-#include "uassert.h"
-
-U_NAMESPACE_BEGIN
-
-static const int32_t MAX_ENCODED_START_YEAR = 32767;
-static const int32_t MIN_ENCODED_START_YEAR = -32768;
-static const int32_t MIN_ENCODED_START = -2147483391; // encodeDate(MIN_ENCODED_START_YEAR, 1, 1, ...);
-
-static const int32_t YEAR_MASK = 0xFFFF0000;
-static const int32_t MONTH_MASK = 0x0000FF00;
-static const int32_t DAY_MASK = 0x000000FF;
-
-static const int32_t MAX_INT32 = 0x7FFFFFFF;
-static const int32_t MIN_INT32 = 0xFFFFFFFF;
-
-static const UChar VAL_FALSE[] = {0x66, 0x61, 0x6c, 0x73, 0x65}; // "false"
-static const UChar VAL_FALSE_LEN = 5;
-
-static UBool isSet(int startDate) {
- return startDate != 0;
-}
-
-static UBool isValidRuleStartDate(int32_t year, int32_t month, int32_t day) {
- return year >= MIN_ENCODED_START_YEAR && year <= MAX_ENCODED_START_YEAR
- && month >= 1 && month <= 12 && day >=1 && day <= 31;
-}
-
-/**
- * Encode year/month/date to a single integer.
- * year is high 16 bits (-32768 to 32767), month is
- * next 8 bits and day of month is last 8 bits.
- *
- * @param year year
- * @param month month (1-base)
- * @param day day of month
- * @return an encoded date.
- */
-static int32_t encodeDate(int32_t year, int32_t month, int32_t day) {
- return year << 16 | month << 8 | day;
-}
-
-static void decodeDate(int32_t encodedDate, int32_t (&fields)[3]) {
- if (encodedDate == MIN_ENCODED_START) {
- fields[0] = MIN_INT32;
- fields[1] = 1;
- fields[2] = 1;
- } else {
- fields[0] = (encodedDate & YEAR_MASK) >> 16;
- fields[1] = (encodedDate & MONTH_MASK) >> 8;
- fields[2] = encodedDate & DAY_MASK;
- }
-}
-
-/**
- * Compare an encoded date with another date specified by year/month/day.
- * @param encoded An encoded date
- * @param year Year of another date
- * @param month Month of another date
- * @param day Day of another date
- * @return -1 when encoded date is earlier, 0 when two dates are same,
- * and 1 when encoded date is later.
- */
-static int32_t compareEncodedDateWithYMD(int encoded, int year, int month, int day) {
- if (year < MIN_ENCODED_START_YEAR) {
- if (encoded == MIN_ENCODED_START) {
- if (year > MIN_INT32 || month > 1 || day > 1) {
- return -1;
- }
- return 0;
- } else {
- return 1;
- }
- } else if (year > MAX_ENCODED_START_YEAR) {
- return -1;
- } else {
- int tmp = encodeDate(year, month, day);
- if (encoded < tmp) {
- return -1;
- } else if (encoded == tmp) {
- return 0;
- } else {
- return 1;
- }
- }
-}
-
-EraRules::EraRules(LocalMemory<int32_t>& eraStartDates, int32_t numEras)
- : numEras(numEras) {
- startDates = std::move(eraStartDates);
- initCurrentEra();
-}
-
-EraRules::~EraRules() {
-}
-
-EraRules* EraRules::createInstance(const char *calType, UBool includeTentativeEra, UErrorCode& status) {
- if(U_FAILURE(status)) {
- return nullptr;
- }
- LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "supplementalData", &status));
- ures_getByKey(rb.getAlias(), "calendarData", rb.getAlias(), &status);
- ures_getByKey(rb.getAlias(), calType, rb.getAlias(), &status);
- ures_getByKey(rb.getAlias(), "eras", rb.getAlias(), &status);
-
- if (U_FAILURE(status)) {
- return nullptr;
- }
-
- int32_t numEras = ures_getSize(rb.getAlias());
- int32_t firstTentativeIdx = MAX_INT32;
-
- LocalMemory<int32_t> startDates(static_cast<int32_t *>(uprv_malloc(numEras * sizeof(int32_t))));
- if (startDates.isNull()) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
- uprv_memset(startDates.getAlias(), 0 , numEras * sizeof(int32_t));
-
- while (ures_hasNext(rb.getAlias())) {
- LocalUResourceBundlePointer eraRuleRes(ures_getNextResource(rb.getAlias(), nullptr, &status));
- if (U_FAILURE(status)) {
- return nullptr;
- }
- const char *eraIdxStr = ures_getKey(eraRuleRes.getAlias());
- char *endp;
- int32_t eraIdx = (int32_t)strtol(eraIdxStr, &endp, 10);
- if ((size_t)(endp - eraIdxStr) != uprv_strlen(eraIdxStr)) {
- status = U_INVALID_FORMAT_ERROR;
- return nullptr;
- }
- if (eraIdx < 0 || eraIdx >= numEras) {
- status = U_INVALID_FORMAT_ERROR;
- return nullptr;
- }
- if (isSet(startDates[eraIdx])) {
- // start date of the index was already set
- status = U_INVALID_FORMAT_ERROR;
- return nullptr;
- }
-
- UBool hasName = TRUE;
- UBool hasEnd = TRUE;
- int32_t len;
- while (ures_hasNext(eraRuleRes.getAlias())) {
- LocalUResourceBundlePointer res(ures_getNextResource(eraRuleRes.getAlias(), nullptr, &status));
- if (U_FAILURE(status)) {
- return nullptr;
- }
- const char *key = ures_getKey(res.getAlias());
- if (uprv_strcmp(key, "start") == 0) {
- const int32_t *fields = ures_getIntVector(res.getAlias(), &len, &status);
- if (U_FAILURE(status)) {
- return nullptr;
- }
- if (len != 3 || !isValidRuleStartDate(fields[0], fields[1], fields[2])) {
- status = U_INVALID_FORMAT_ERROR;
- return nullptr;
- }
- startDates[eraIdx] = encodeDate(fields[0], fields[1], fields[2]);
- } else if (uprv_strcmp(key, "named") == 0) {
- const UChar *val = ures_getString(res.getAlias(), &len, &status);
- if (u_strncmp(val, VAL_FALSE, VAL_FALSE_LEN) == 0) {
- hasName = FALSE;
- }
- } else if (uprv_strcmp(key, "end") == 0) {
- hasEnd = TRUE;
- }
- }
-
- if (isSet(startDates[eraIdx])) {
- if (hasEnd) {
- // This implementation assumes either start or end is available, not both.
- // For now, just ignore the end rule.
- }
- } else {
- if (hasEnd) {
- if (eraIdx != 0) {
- // This implementation does not support end only rule for eras other than
- // the first one.
- status = U_INVALID_FORMAT_ERROR;
- return nullptr;
- }
- U_ASSERT(eraIdx == 0);
- startDates[eraIdx] = MIN_ENCODED_START;
- } else {
- status = U_INVALID_FORMAT_ERROR;
- return nullptr;
- }
- }
-
- if (hasName) {
- if (eraIdx >= firstTentativeIdx) {
- status = U_INVALID_FORMAT_ERROR;
- return nullptr;
- }
- } else {
- if (eraIdx < firstTentativeIdx) {
- firstTentativeIdx = eraIdx;
- }
- }
- }
-
- EraRules *result;
- if (firstTentativeIdx < MAX_INT32 && !includeTentativeEra) {
- result = new EraRules(startDates, firstTentativeIdx);
- } else {
- result = new EraRules(startDates, numEras);
- }
-
- if (result == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
- return result;
-}
-
-void EraRules::getStartDate(int32_t eraIdx, int32_t (&fields)[3], UErrorCode& status) const {
- if(U_FAILURE(status)) {
- return;
- }
- if (eraIdx < 0 || eraIdx >= numEras) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return;
- }
- decodeDate(startDates[eraIdx], fields);
-}
-
-int32_t EraRules::getStartYear(int32_t eraIdx, UErrorCode& status) const {
- int year = MAX_INT32; // bogus value
- if(U_FAILURE(status)) {
- return year;
- }
- if (eraIdx < 0 || eraIdx >= numEras) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return year;
- }
- int fields[3];
- decodeDate(startDates[eraIdx], fields);
- year = fields[0];
-
- return year;
-}
-
-int32_t EraRules::getEraIndex(int32_t year, int32_t month, int32_t day, UErrorCode& status) const {
- if(U_FAILURE(status)) {
- return -1;
- }
-
- if (month < 1 || month > 12 || day < 1 || day > 31) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return -1;
- }
- int32_t high = numEras; // last index + 1
- int32_t low;
-
- // Short circuit for recent years. Most modern computations will
- // occur in the last few eras.
- if (compareEncodedDateWithYMD(startDates[getCurrentEraIndex()], year, month, day) <= 0) {
- low = getCurrentEraIndex();
- } else {
- low = 0;
- }
-
- // Do binary search
- while (low < high - 1) {
- int i = (low + high) / 2;
- if (compareEncodedDateWithYMD(startDates[i], year, month, day) <= 0) {
- low = i;
- } else {
- high = i;
- }
- }
- return low;
-}
-
-void EraRules::initCurrentEra() {
- // Compute local wall time in millis using ICU's default time zone.
- UErrorCode ec = U_ZERO_ERROR;
- UDate localMillis = ucal_getNow();
-
- int32_t rawOffset, dstOffset;
- TimeZone* zone = TimeZone::createDefault();
- // If we failed to create the default time zone, we are in a bad state and don't
- // really have many options. Carry on using UTC millis as a fallback.
- if (zone != nullptr) {
- zone->getOffset(localMillis, FALSE, rawOffset, dstOffset, ec);
- delete zone;
- localMillis += (rawOffset + dstOffset);
- }
-
- int year, month0, dom, dow, doy, mid;
- Grego::timeToFields(localMillis, year, month0, dom, dow, doy, mid);
- int currentEncodedDate = encodeDate(year, month0 + 1 /* changes to 1-base */, dom);
- int eraIdx = numEras - 1;
- while (eraIdx > 0) {
- if (currentEncodedDate >= startDates[eraIdx]) {
- break;
- }
- eraIdx--;
- }
- // Note: current era could be before the first era.
- // In this case, this implementation returns the first era index (0).
- currentEra = eraIdx;
-}
-
-U_NAMESPACE_END
-#endif /* #if !UCONFIG_NO_FORMATTING */
-
-
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#include <utility>
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include <stdlib.h>
+#include "unicode/ucal.h"
+#include "unicode/ures.h"
+#include "unicode/ustring.h"
+#include "unicode/timezone.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "erarules.h"
+#include "gregoimp.h"
+#include "uassert.h"
+
+U_NAMESPACE_BEGIN
+
+static const int32_t MAX_ENCODED_START_YEAR = 32767;
+static const int32_t MIN_ENCODED_START_YEAR = -32768;
+static const int32_t MIN_ENCODED_START = -2147483391; // encodeDate(MIN_ENCODED_START_YEAR, 1, 1, ...);
+
+static const int32_t YEAR_MASK = 0xFFFF0000;
+static const int32_t MONTH_MASK = 0x0000FF00;
+static const int32_t DAY_MASK = 0x000000FF;
+
+static const int32_t MAX_INT32 = 0x7FFFFFFF;
+static const int32_t MIN_INT32 = 0xFFFFFFFF;
+
+static const UChar VAL_FALSE[] = {0x66, 0x61, 0x6c, 0x73, 0x65}; // "false"
+static const UChar VAL_FALSE_LEN = 5;
+
+static UBool isSet(int startDate) {
+ return startDate != 0;
+}
+
+static UBool isValidRuleStartDate(int32_t year, int32_t month, int32_t day) {
+ return year >= MIN_ENCODED_START_YEAR && year <= MAX_ENCODED_START_YEAR
+ && month >= 1 && month <= 12 && day >=1 && day <= 31;
+}
+
+/**
+ * Encode year/month/date to a single integer.
+ * year is high 16 bits (-32768 to 32767), month is
+ * next 8 bits and day of month is last 8 bits.
+ *
+ * @param year year
+ * @param month month (1-base)
+ * @param day day of month
+ * @return an encoded date.
+ */
+static int32_t encodeDate(int32_t year, int32_t month, int32_t day) {
+ return year << 16 | month << 8 | day;
+}
+
+static void decodeDate(int32_t encodedDate, int32_t (&fields)[3]) {
+ if (encodedDate == MIN_ENCODED_START) {
+ fields[0] = MIN_INT32;
+ fields[1] = 1;
+ fields[2] = 1;
+ } else {
+ fields[0] = (encodedDate & YEAR_MASK) >> 16;
+ fields[1] = (encodedDate & MONTH_MASK) >> 8;
+ fields[2] = encodedDate & DAY_MASK;
+ }
+}
+
+/**
+ * Compare an encoded date with another date specified by year/month/day.
+ * @param encoded An encoded date
+ * @param year Year of another date
+ * @param month Month of another date
+ * @param day Day of another date
+ * @return -1 when encoded date is earlier, 0 when two dates are same,
+ * and 1 when encoded date is later.
+ */
+static int32_t compareEncodedDateWithYMD(int encoded, int year, int month, int day) {
+ if (year < MIN_ENCODED_START_YEAR) {
+ if (encoded == MIN_ENCODED_START) {
+ if (year > MIN_INT32 || month > 1 || day > 1) {
+ return -1;
+ }
+ return 0;
+ } else {
+ return 1;
+ }
+ } else if (year > MAX_ENCODED_START_YEAR) {
+ return -1;
+ } else {
+ int tmp = encodeDate(year, month, day);
+ if (encoded < tmp) {
+ return -1;
+ } else if (encoded == tmp) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+}
+
+EraRules::EraRules(LocalMemory<int32_t>& eraStartDates, int32_t numEras)
+ : numEras(numEras) {
+ startDates = std::move(eraStartDates);
+ initCurrentEra();
+}
+
+EraRules::~EraRules() {
+}
+
+EraRules* EraRules::createInstance(const char *calType, UBool includeTentativeEra, UErrorCode& status) {
+ if(U_FAILURE(status)) {
+ return nullptr;
+ }
+ LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "supplementalData", &status));
+ ures_getByKey(rb.getAlias(), "calendarData", rb.getAlias(), &status);
+ ures_getByKey(rb.getAlias(), calType, rb.getAlias(), &status);
+ ures_getByKey(rb.getAlias(), "eras", rb.getAlias(), &status);
+
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+
+ int32_t numEras = ures_getSize(rb.getAlias());
+ int32_t firstTentativeIdx = MAX_INT32;
+
+ LocalMemory<int32_t> startDates(static_cast<int32_t *>(uprv_malloc(numEras * sizeof(int32_t))));
+ if (startDates.isNull()) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+ uprv_memset(startDates.getAlias(), 0 , numEras * sizeof(int32_t));
+
+ while (ures_hasNext(rb.getAlias())) {
+ LocalUResourceBundlePointer eraRuleRes(ures_getNextResource(rb.getAlias(), nullptr, &status));
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ const char *eraIdxStr = ures_getKey(eraRuleRes.getAlias());
+ char *endp;
+ int32_t eraIdx = (int32_t)strtol(eraIdxStr, &endp, 10);
+ if ((size_t)(endp - eraIdxStr) != uprv_strlen(eraIdxStr)) {
+ status = U_INVALID_FORMAT_ERROR;
+ return nullptr;
+ }
+ if (eraIdx < 0 || eraIdx >= numEras) {
+ status = U_INVALID_FORMAT_ERROR;
+ return nullptr;
+ }
+ if (isSet(startDates[eraIdx])) {
+ // start date of the index was already set
+ status = U_INVALID_FORMAT_ERROR;
+ return nullptr;
+ }
+
+ UBool hasName = TRUE;
+ UBool hasEnd = TRUE;
+ int32_t len;
+ while (ures_hasNext(eraRuleRes.getAlias())) {
+ LocalUResourceBundlePointer res(ures_getNextResource(eraRuleRes.getAlias(), nullptr, &status));
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ const char *key = ures_getKey(res.getAlias());
+ if (uprv_strcmp(key, "start") == 0) {
+ const int32_t *fields = ures_getIntVector(res.getAlias(), &len, &status);
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ if (len != 3 || !isValidRuleStartDate(fields[0], fields[1], fields[2])) {
+ status = U_INVALID_FORMAT_ERROR;
+ return nullptr;
+ }
+ startDates[eraIdx] = encodeDate(fields[0], fields[1], fields[2]);
+ } else if (uprv_strcmp(key, "named") == 0) {
+ const UChar *val = ures_getString(res.getAlias(), &len, &status);
+ if (u_strncmp(val, VAL_FALSE, VAL_FALSE_LEN) == 0) {
+ hasName = FALSE;
+ }
+ } else if (uprv_strcmp(key, "end") == 0) {
+ hasEnd = TRUE;
+ }
+ }
+
+ if (isSet(startDates[eraIdx])) {
+ if (hasEnd) {
+ // This implementation assumes either start or end is available, not both.
+ // For now, just ignore the end rule.
+ }
+ } else {
+ if (hasEnd) {
+ if (eraIdx != 0) {
+ // This implementation does not support end only rule for eras other than
+ // the first one.
+ status = U_INVALID_FORMAT_ERROR;
+ return nullptr;
+ }
+ U_ASSERT(eraIdx == 0);
+ startDates[eraIdx] = MIN_ENCODED_START;
+ } else {
+ status = U_INVALID_FORMAT_ERROR;
+ return nullptr;
+ }
+ }
+
+ if (hasName) {
+ if (eraIdx >= firstTentativeIdx) {
+ status = U_INVALID_FORMAT_ERROR;
+ return nullptr;
+ }
+ } else {
+ if (eraIdx < firstTentativeIdx) {
+ firstTentativeIdx = eraIdx;
+ }
+ }
+ }
+
+ EraRules *result;
+ if (firstTentativeIdx < MAX_INT32 && !includeTentativeEra) {
+ result = new EraRules(startDates, firstTentativeIdx);
+ } else {
+ result = new EraRules(startDates, numEras);
+ }
+
+ if (result == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return result;
+}
+
+void EraRules::getStartDate(int32_t eraIdx, int32_t (&fields)[3], UErrorCode& status) const {
+ if(U_FAILURE(status)) {
+ return;
+ }
+ if (eraIdx < 0 || eraIdx >= numEras) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ decodeDate(startDates[eraIdx], fields);
+}
+
+int32_t EraRules::getStartYear(int32_t eraIdx, UErrorCode& status) const {
+ int year = MAX_INT32; // bogus value
+ if(U_FAILURE(status)) {
+ return year;
+ }
+ if (eraIdx < 0 || eraIdx >= numEras) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return year;
+ }
+ int fields[3];
+ decodeDate(startDates[eraIdx], fields);
+ year = fields[0];
+
+ return year;
+}
+
+int32_t EraRules::getEraIndex(int32_t year, int32_t month, int32_t day, UErrorCode& status) const {
+ if(U_FAILURE(status)) {
+ return -1;
+ }
+
+ if (month < 1 || month > 12 || day < 1 || day > 31) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
+ int32_t high = numEras; // last index + 1
+ int32_t low;
+
+ // Short circuit for recent years. Most modern computations will
+ // occur in the last few eras.
+ if (compareEncodedDateWithYMD(startDates[getCurrentEraIndex()], year, month, day) <= 0) {
+ low = getCurrentEraIndex();
+ } else {
+ low = 0;
+ }
+
+ // Do binary search
+ while (low < high - 1) {
+ int i = (low + high) / 2;
+ if (compareEncodedDateWithYMD(startDates[i], year, month, day) <= 0) {
+ low = i;
+ } else {
+ high = i;
+ }
+ }
+ return low;
+}
+
+void EraRules::initCurrentEra() {
+ // Compute local wall time in millis using ICU's default time zone.
+ UErrorCode ec = U_ZERO_ERROR;
+ UDate localMillis = ucal_getNow();
+
+ int32_t rawOffset, dstOffset;
+ TimeZone* zone = TimeZone::createDefault();
+ // If we failed to create the default time zone, we are in a bad state and don't
+ // really have many options. Carry on using UTC millis as a fallback.
+ if (zone != nullptr) {
+ zone->getOffset(localMillis, FALSE, rawOffset, dstOffset, ec);
+ delete zone;
+ localMillis += (rawOffset + dstOffset);
+ }
+
+ int year, month0, dom, dow, doy, mid;
+ Grego::timeToFields(localMillis, year, month0, dom, dow, doy, mid);
+ int currentEncodedDate = encodeDate(year, month0 + 1 /* changes to 1-base */, dom);
+ int eraIdx = numEras - 1;
+ while (eraIdx > 0) {
+ if (currentEncodedDate >= startDates[eraIdx]) {
+ break;
+ }
+ eraIdx--;
+ }
+ // Note: current era could be before the first era.
+ // In this case, this implementation returns the first era index (0).
+ currentEra = eraIdx;
+}
+
+U_NAMESPACE_END
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+
diff --git a/contrib/libs/icu/i18n/erarules.h b/contrib/libs/icu/i18n/erarules.h
index 74b7862da4..9baec63225 100644
--- a/contrib/libs/icu/i18n/erarules.h
+++ b/contrib/libs/icu/i18n/erarules.h
@@ -1,99 +1,99 @@
-// © 2018 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html
-
-#ifndef ERARULES_H_
-#define ERARULES_H_
-
-#include "unicode/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/localpointer.h"
-#include "unicode/uobject.h"
-#include "cmemory.h"
-
-U_NAMESPACE_BEGIN
-
-// Export an explicit template instantiation of LocalMemory used as a data member of EraRules.
-// 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.
-#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
-#if defined(_MSC_VER)
-// Ignore warning 4661 as LocalPointerBase does not use operator== or operator!=
-#pragma warning(push)
-#pragma warning(disable: 4661)
-#endif
-template class U_I18N_API LocalPointerBase<int32_t>;
-template class U_I18N_API LocalMemory<int32_t>;
-#if defined(_MSC_VER)
-#pragma warning(pop)
-#endif
-#endif
-
-class U_I18N_API EraRules : public UMemory {
-public:
- ~EraRules();
-
- static EraRules* createInstance(const char *calType, UBool includeTentativeEra, UErrorCode& status);
-
- /**
- * Gets number of effective eras
- * @return number of effective eras
- */
- inline int32_t getNumberOfEras() const {
- return numEras;
- }
-
- /**
- * Gets start date of an era
- * @param eraIdx Era index
- * @param fields Receives date fields. The result includes values of year, month,
- * day of month in this order. When an era has no start date, the result
- * will be January 1st in year whose value is minimum integer.
- * @param status Receives status.
- */
- void getStartDate(int32_t eraIdx, int32_t (&fields)[3], UErrorCode& status) const;
-
- /**
- * Gets start year of an era
- * @param eraIdx Era index
- * @param status Receives status.
- * @return The first year of an era. When a era has no start date, minimum int32
- * value is returned.
- */
- int32_t getStartYear(int32_t eraIdx, UErrorCode& status) const;
-
- /**
- * Returns era index for the specified year/month/day.
- * @param year Year
- * @param month Month (1-base)
- * @param day Day of month
- * @param status Receives status
- * @return era index (or 0, when the specified date is before the first era)
- */
- int32_t getEraIndex(int32_t year, int32_t month, int32_t day, UErrorCode& status) const;
-
- /**
- * Gets the current era index. This is calculated only once for an instance of
- * EraRules. The current era calculation is based on the default time zone at
- * the time of instantiation.
- *
- * @return era index of current era (or 0, when current date is before the first era)
- */
- inline int32_t getCurrentEraIndex() const {
- return currentEra;
- }
-
-private:
- EraRules(LocalMemory<int32_t>& eraStartDates, int32_t numEra);
-
- void initCurrentEra();
-
- LocalMemory<int32_t> startDates;
- int32_t numEras;
- int32_t currentEra;
-};
-
-U_NAMESPACE_END
-#endif /* #if !UCONFIG_NO_FORMATTING */
-#endif /* ERARULES_H_ */
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#ifndef ERARULES_H_
+#define ERARULES_H_
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/localpointer.h"
+#include "unicode/uobject.h"
+#include "cmemory.h"
+
+U_NAMESPACE_BEGIN
+
+// Export an explicit template instantiation of LocalMemory used as a data member of EraRules.
+// 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.
+#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
+#if defined(_MSC_VER)
+// Ignore warning 4661 as LocalPointerBase does not use operator== or operator!=
+#pragma warning(push)
+#pragma warning(disable: 4661)
+#endif
+template class U_I18N_API LocalPointerBase<int32_t>;
+template class U_I18N_API LocalMemory<int32_t>;
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+#endif
+
+class U_I18N_API EraRules : public UMemory {
+public:
+ ~EraRules();
+
+ static EraRules* createInstance(const char *calType, UBool includeTentativeEra, UErrorCode& status);
+
+ /**
+ * Gets number of effective eras
+ * @return number of effective eras
+ */
+ inline int32_t getNumberOfEras() const {
+ return numEras;
+ }
+
+ /**
+ * Gets start date of an era
+ * @param eraIdx Era index
+ * @param fields Receives date fields. The result includes values of year, month,
+ * day of month in this order. When an era has no start date, the result
+ * will be January 1st in year whose value is minimum integer.
+ * @param status Receives status.
+ */
+ void getStartDate(int32_t eraIdx, int32_t (&fields)[3], UErrorCode& status) const;
+
+ /**
+ * Gets start year of an era
+ * @param eraIdx Era index
+ * @param status Receives status.
+ * @return The first year of an era. When a era has no start date, minimum int32
+ * value is returned.
+ */
+ int32_t getStartYear(int32_t eraIdx, UErrorCode& status) const;
+
+ /**
+ * Returns era index for the specified year/month/day.
+ * @param year Year
+ * @param month Month (1-base)
+ * @param day Day of month
+ * @param status Receives status
+ * @return era index (or 0, when the specified date is before the first era)
+ */
+ int32_t getEraIndex(int32_t year, int32_t month, int32_t day, UErrorCode& status) const;
+
+ /**
+ * Gets the current era index. This is calculated only once for an instance of
+ * EraRules. The current era calculation is based on the default time zone at
+ * the time of instantiation.
+ *
+ * @return era index of current era (or 0, when current date is before the first era)
+ */
+ inline int32_t getCurrentEraIndex() const {
+ return currentEra;
+ }
+
+private:
+ EraRules(LocalMemory<int32_t>& eraStartDates, int32_t numEra);
+
+ void initCurrentEra();
+
+ LocalMemory<int32_t> startDates;
+ int32_t numEras;
+ int32_t currentEra;
+};
+
+U_NAMESPACE_END
+#endif /* #if !UCONFIG_NO_FORMATTING */
+#endif /* ERARULES_H_ */
diff --git a/contrib/libs/icu/i18n/esctrn.cpp b/contrib/libs/icu/i18n/esctrn.cpp
index ba0e4c2c7b..dd947dfcb9 100644
--- a/contrib/libs/icu/i18n/esctrn.cpp
+++ b/contrib/libs/icu/i18n/esctrn.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -122,7 +122,7 @@ EscapeTransliterator::~EscapeTransliterator() {
/**
* Transliterator API.
*/
-EscapeTransliterator* EscapeTransliterator::clone() const {
+EscapeTransliterator* EscapeTransliterator::clone() const {
return new EscapeTransliterator(*this);
}
diff --git a/contrib/libs/icu/i18n/esctrn.h b/contrib/libs/icu/i18n/esctrn.h
index 2a2c6dcfe9..93a62bcc4e 100644
--- a/contrib/libs/icu/i18n/esctrn.h
+++ b/contrib/libs/icu/i18n/esctrn.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -115,7 +115,7 @@ class EscapeTransliterator : public Transliterator {
/**
* Transliterator API.
*/
- virtual EscapeTransliterator* clone() const;
+ virtual EscapeTransliterator* clone() const;
/**
* ICU "poor man's RTTI", returns a UClassID for the actual class.
diff --git a/contrib/libs/icu/i18n/ethpccal.cpp b/contrib/libs/icu/i18n/ethpccal.cpp
index 7c7c0ba37b..51583db1b2 100644
--- a/contrib/libs/icu/i18n/ethpccal.cpp
+++ b/contrib/libs/icu/i18n/ethpccal.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -46,7 +46,7 @@ EthiopicCalendar::~EthiopicCalendar()
{
}
-EthiopicCalendar*
+EthiopicCalendar*
EthiopicCalendar::clone() const
{
return new EthiopicCalendar(*this);
diff --git a/contrib/libs/icu/i18n/ethpccal.h b/contrib/libs/icu/i18n/ethpccal.h
index d1e8f424b5..1c82c6766a 100644
--- a/contrib/libs/icu/i18n/ethpccal.h
+++ b/contrib/libs/icu/i18n/ethpccal.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -141,7 +141,7 @@ public:
* @return return a polymorphic copy of this calendar.
* @internal
*/
- virtual EthiopicCalendar* clone() const;
+ virtual EthiopicCalendar* clone() const;
/**
* return the calendar type, "ethiopic"
diff --git a/contrib/libs/icu/i18n/fmtable.cpp b/contrib/libs/icu/i18n/fmtable.cpp
index dbfd3c26ba..28a75530cc 100644
--- a/contrib/libs/icu/i18n/fmtable.cpp
+++ b/contrib/libs/icu/i18n/fmtable.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -19,7 +19,7 @@
#if !UCONFIG_NO_FORMATTING
-#include <cstdlib>
+#include <cstdlib>
#include <math.h>
#include "unicode/fmtable.h"
#include "unicode/ustring.h"
@@ -30,7 +30,7 @@
#include "cmemory.h"
#include "cstring.h"
#include "fmtableimp.h"
-#include "number_decimalquantity.h"
+#include "number_decimalquantity.h"
// *****************************************************************************
// class Formattable
@@ -40,9 +40,9 @@ U_NAMESPACE_BEGIN
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Formattable)
-using number::impl::DecimalQuantity;
-
+using number::impl::DecimalQuantity;
+
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
// NOTE: As of 3.0, there are limitations to the UObject API. It does
@@ -105,7 +105,7 @@ void Formattable::init() {
fValue.fInt64 = 0;
fType = kLong;
fDecimalStr = NULL;
- fDecimalQuantity = NULL;
+ fDecimalQuantity = NULL;
fBogus.setToBogus();
}
@@ -259,8 +259,8 @@ Formattable::operator=(const Formattable& source)
}
UErrorCode status = U_ZERO_ERROR;
- if (source.fDecimalQuantity != NULL) {
- fDecimalQuantity = new DecimalQuantity(*source.fDecimalQuantity);
+ if (source.fDecimalQuantity != NULL) {
+ fDecimalQuantity = new DecimalQuantity(*source.fDecimalQuantity);
}
if (source.fDecimalStr != NULL) {
fDecimalStr = new CharString(*source.fDecimalStr, status);
@@ -358,9 +358,9 @@ void Formattable::dispose()
delete fDecimalStr;
fDecimalStr = NULL;
-
- delete fDecimalQuantity;
- fDecimalQuantity = NULL;
+
+ delete fDecimalQuantity;
+ fDecimalQuantity = NULL;
}
Formattable *
@@ -462,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 && fDecimalQuantity != NULL) {
- if (fDecimalQuantity->fitsInLong(true)) {
- return fDecimalQuantity->toLong();
+ } else if (fabs(fValue.fDouble) > U_DOUBLE_MAX_EXACT_INT && fDecimalQuantity != NULL) {
+ if (fDecimalQuantity->fitsInLong(true)) {
+ return fDecimalQuantity->toLong();
} else {
- // Unexpected
+ // Unexpected
status = U_INVALID_FORMAT_ERROR;
- return fDecimalQuantity->isNegative() ? U_INT64_MIN : U_INT64_MAX;
+ return fDecimalQuantity->isNegative() ? U_INT64_MIN : U_INT64_MAX;
}
} else {
return (int64_t)fValue.fDouble;
@@ -711,90 +711,90 @@ StringPiece Formattable::getDecimalNumber(UErrorCode &status) {
CharString *Formattable::internalGetCharString(UErrorCode &status) {
if(fDecimalStr == NULL) {
- if (fDecimalQuantity == 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.
//
- LocalPointer<DecimalQuantity> dq(new DecimalQuantity(), status);
- if (U_FAILURE(status)) { return nullptr; }
- populateDecimalQuantity(*dq, status);
- if (U_FAILURE(status)) { return nullptr; }
- fDecimalQuantity = dq.orphan();
+ LocalPointer<DecimalQuantity> 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;
}
- // 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->isInfinite()) {
- fDecimalStr->append("Infinity", status);
- } else if (fDecimalQuantity->isNaN()) {
- fDecimalStr->append("NaN", status);
- } else if (fDecimalQuantity->isZeroish()) {
- fDecimalStr->append("0", -1, status);
- } else if (fType==kLong || fType==kInt64 || // use toPlainString for integer types
- (fDecimalQuantity->getMagnitude() != INT32_MIN && std::abs(fDecimalQuantity->getMagnitude()) < 5)) {
- fDecimalStr->appendInvariantChars(fDecimalQuantity->toPlainString(), status);
- } else {
- fDecimalStr->appendInvariantChars(fDecimalQuantity->toScientificString(), 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->isInfinite()) {
+ fDecimalStr->append("Infinity", status);
+ } else if (fDecimalQuantity->isNaN()) {
+ fDecimalStr->append("NaN", status);
+ } else if (fDecimalQuantity->isZeroish()) {
+ fDecimalStr->append("0", -1, status);
+ } else if (fType==kLong || fType==kInt64 || // use toPlainString for integer types
+ (fDecimalQuantity->getMagnitude() != INT32_MIN && 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;
- }
-
- 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::populateDecimalQuantity(number::impl::DecimalQuantity& output, UErrorCode& status) const {
+ if (fDecimalQuantity != nullptr) {
+ output = *fDecimalQuantity;
+ return;
+ }
+
+ 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::adoptDecimalQuantity(DecimalQuantity *dq) {
- if (fDecimalQuantity != NULL) {
- delete fDecimalQuantity;
- }
- fDecimalQuantity = dq;
- if (dq == 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 (fDecimalQuantity->fitsInLong()) {
- fValue.fInt64 = fDecimalQuantity->toLong();
- if (fValue.fInt64 <= INT32_MAX && fValue.fInt64 >= INT32_MIN) {
- fType = kLong;
- } else {
- fType = kInt64;
- }
+ // 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 = fDecimalQuantity->toDouble();
+ fValue.fDouble = fDecimalQuantity->toDouble();
}
}
@@ -807,12 +807,12 @@ Formattable::setDecimalNumber(StringPiece numberString, UErrorCode &status) {
}
dispose();
- auto* dq = new DecimalQuantity();
- dq->setToDecNumber(numberString, status);
- adoptDecimalQuantity(dq);
+ 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 fDecimalQuantity.
+ // If we are asked for the string, we will regenerate one from fDecimalQuantity.
}
#if 0
diff --git a/contrib/libs/icu/i18n/fmtable_cnv.cpp b/contrib/libs/icu/i18n/fmtable_cnv.cpp
index 9a64792779..ff623c0dd4 100644
--- a/contrib/libs/icu/i18n/fmtable_cnv.cpp
+++ b/contrib/libs/icu/i18n/fmtable_cnv.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/fmtableimp.h b/contrib/libs/icu/i18n/fmtableimp.h
index 2707d6ece2..62c46d5470 100644
--- a/contrib/libs/icu/i18n/fmtableimp.h
+++ b/contrib/libs/icu/i18n/fmtableimp.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -10,10 +10,10 @@
#ifndef FMTABLEIMP_H
#define FMTABLEIMP_H
-#include "number_decimalquantity.h"
-
-#if !UCONFIG_NO_FORMATTING
+#include "number_decimalquantity.h"
+#if !UCONFIG_NO_FORMATTING
+
U_NAMESPACE_BEGIN
/**
@@ -27,5 +27,5 @@ static const int64_t MAX_INT64_IN_DOUBLE = 0x001FFFFFFFFFFFFFLL;
U_NAMESPACE_END
-#endif // #if !UCONFIG_NO_FORMATTING
+#endif // #if !UCONFIG_NO_FORMATTING
#endif
diff --git a/contrib/libs/icu/i18n/format.cpp b/contrib/libs/icu/i18n/format.cpp
index e5abbe9eb0..1b51055d83 100644
--- a/contrib/libs/icu/i18n/format.cpp
+++ b/contrib/libs/icu/i18n/format.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/formatted_string_builder.cpp b/contrib/libs/icu/i18n/formatted_string_builder.cpp
index 5aabc31cc4..5d7d705b36 100644
--- a/contrib/libs/icu/i18n/formatted_string_builder.cpp
+++ b/contrib/libs/icu/i18n/formatted_string_builder.cpp
@@ -1,442 +1,442 @@
-// © 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
-
-#include "formatted_string_builder.h"
-#include "unicode/ustring.h"
-#include "unicode/utf16.h"
-#include "unicode/unum.h" // for UNumberFormatFields literals
-
-namespace {
-
-// A version of uprv_memcpy that checks for length 0.
-// By default, uprv_memcpy requires a length of at least 1.
-inline void uprv_memcpy2(void* dest, const void* src, size_t len) {
- if (len > 0) {
- uprv_memcpy(dest, src, len);
- }
-}
-
-// A version of uprv_memmove that checks for length 0.
-// By default, uprv_memmove requires a length of at least 1.
-inline void uprv_memmove2(void* dest, const void* src, size_t len) {
- if (len > 0) {
- uprv_memmove(dest, src, len);
- }
-}
-
-} // namespace
-
-
-U_NAMESPACE_BEGIN
-
-FormattedStringBuilder::FormattedStringBuilder() {
-#if U_DEBUG
- // Initializing the memory to non-zero helps catch some bugs that involve
- // reading from an improperly terminated string.
- for (int32_t i=0; i<getCapacity(); i++) {
- getCharPtr()[i] = 1;
- }
-#endif
-}
-
-FormattedStringBuilder::~FormattedStringBuilder() {
- if (fUsingHeap) {
- uprv_free(fChars.heap.ptr);
- uprv_free(fFields.heap.ptr);
- }
-}
-
-FormattedStringBuilder::FormattedStringBuilder(const FormattedStringBuilder &other) {
- *this = other;
-}
-
-FormattedStringBuilder &FormattedStringBuilder::operator=(const FormattedStringBuilder &other) {
- // Check for self-assignment
- if (this == &other) {
- return *this;
- }
-
- // Continue with deallocation and copying
- if (fUsingHeap) {
- uprv_free(fChars.heap.ptr);
- uprv_free(fFields.heap.ptr);
- fUsingHeap = false;
- }
-
- int32_t capacity = other.getCapacity();
- if (capacity > DEFAULT_CAPACITY) {
- // FIXME: uprv_malloc
- // C++ note: malloc appears in two places: here and in prepareForInsertHelper.
- auto newChars = static_cast<char16_t *> (uprv_malloc(sizeof(char16_t) * capacity));
- auto newFields = static_cast<Field *>(uprv_malloc(sizeof(Field) * capacity));
- if (newChars == nullptr || newFields == nullptr) {
- // UErrorCode is not available; fail silently.
- uprv_free(newChars);
- uprv_free(newFields);
- *this = FormattedStringBuilder(); // can't fail
- return *this;
- }
-
- fUsingHeap = true;
- fChars.heap.capacity = capacity;
- fChars.heap.ptr = newChars;
- fFields.heap.capacity = capacity;
- fFields.heap.ptr = newFields;
- }
-
- uprv_memcpy2(getCharPtr(), other.getCharPtr(), sizeof(char16_t) * capacity);
- uprv_memcpy2(getFieldPtr(), other.getFieldPtr(), sizeof(Field) * capacity);
-
- fZero = other.fZero;
- fLength = other.fLength;
- return *this;
-}
-
-int32_t FormattedStringBuilder::length() const {
- return fLength;
-}
-
-int32_t FormattedStringBuilder::codePointCount() const {
- return u_countChar32(getCharPtr() + fZero, fLength);
-}
-
-UChar32 FormattedStringBuilder::getFirstCodePoint() const {
- if (fLength == 0) {
- return -1;
- }
- UChar32 cp;
- U16_GET(getCharPtr() + fZero, 0, 0, fLength, cp);
- return cp;
-}
-
-UChar32 FormattedStringBuilder::getLastCodePoint() const {
- if (fLength == 0) {
- return -1;
- }
- int32_t offset = fLength;
- U16_BACK_1(getCharPtr() + fZero, 0, offset);
- UChar32 cp;
- U16_GET(getCharPtr() + fZero, 0, offset, fLength, cp);
- return cp;
-}
-
-UChar32 FormattedStringBuilder::codePointAt(int32_t index) const {
- UChar32 cp;
- U16_GET(getCharPtr() + fZero, 0, index, fLength, cp);
- return cp;
-}
-
-UChar32 FormattedStringBuilder::codePointBefore(int32_t index) const {
- int32_t offset = index;
- U16_BACK_1(getCharPtr() + fZero, 0, offset);
- UChar32 cp;
- U16_GET(getCharPtr() + fZero, 0, offset, fLength, cp);
- return cp;
-}
-
-FormattedStringBuilder &FormattedStringBuilder::clear() {
- // TODO: Reset the heap here?
- fZero = getCapacity() / 2;
- fLength = 0;
- return *this;
-}
-
-int32_t
-FormattedStringBuilder::insertCodePoint(int32_t index, UChar32 codePoint, Field field, UErrorCode &status) {
- int32_t count = U16_LENGTH(codePoint);
- int32_t position = prepareForInsert(index, count, status);
- if (U_FAILURE(status)) {
- return count;
- }
- if (count == 1) {
- getCharPtr()[position] = (char16_t) codePoint;
- getFieldPtr()[position] = field;
- } else {
- getCharPtr()[position] = U16_LEAD(codePoint);
- getCharPtr()[position + 1] = U16_TRAIL(codePoint);
- getFieldPtr()[position] = getFieldPtr()[position + 1] = field;
- }
- return count;
-}
-
-int32_t FormattedStringBuilder::insert(int32_t index, const UnicodeString &unistr, Field field,
- UErrorCode &status) {
- if (unistr.length() == 0) {
- // Nothing to insert.
- return 0;
- } else if (unistr.length() == 1) {
- // Fast path: insert using insertCodePoint.
- return insertCodePoint(index, unistr.charAt(0), field, status);
- } else {
- return insert(index, unistr, 0, unistr.length(), field, status);
- }
-}
-
-int32_t
-FormattedStringBuilder::insert(int32_t index, const UnicodeString &unistr, int32_t start, int32_t end,
- Field field, UErrorCode &status) {
- int32_t count = end - start;
- int32_t position = prepareForInsert(index, count, status);
- if (U_FAILURE(status)) {
- return count;
- }
- for (int32_t i = 0; i < count; i++) {
- getCharPtr()[position + i] = unistr.charAt(start + i);
- getFieldPtr()[position + i] = field;
- }
- return count;
-}
-
-int32_t
-FormattedStringBuilder::splice(int32_t startThis, int32_t endThis, const UnicodeString &unistr,
- int32_t startOther, int32_t endOther, Field field, UErrorCode& status) {
- int32_t thisLength = endThis - startThis;
- int32_t otherLength = endOther - startOther;
- int32_t count = otherLength - thisLength;
- int32_t position;
- if (count > 0) {
- // Overall, chars need to be added.
- position = prepareForInsert(startThis, count, status);
- } else {
- // Overall, chars need to be removed or kept the same.
- position = remove(startThis, -count);
- }
- if (U_FAILURE(status)) {
- return count;
- }
- for (int32_t i = 0; i < otherLength; i++) {
- getCharPtr()[position + i] = unistr.charAt(startOther + i);
- getFieldPtr()[position + i] = field;
- }
- return count;
-}
-
-int32_t FormattedStringBuilder::append(const FormattedStringBuilder &other, UErrorCode &status) {
- return insert(fLength, other, status);
-}
-
-int32_t
-FormattedStringBuilder::insert(int32_t index, const FormattedStringBuilder &other, UErrorCode &status) {
- if (this == &other) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return 0;
- }
- int32_t count = other.fLength;
- if (count == 0) {
- // Nothing to insert.
- return 0;
- }
- int32_t position = prepareForInsert(index, count, status);
- if (U_FAILURE(status)) {
- return count;
- }
- for (int32_t i = 0; i < count; i++) {
- getCharPtr()[position + i] = other.charAt(i);
- getFieldPtr()[position + i] = other.fieldAt(i);
- }
- return count;
-}
-
-void FormattedStringBuilder::writeTerminator(UErrorCode& status) {
- int32_t position = prepareForInsert(fLength, 1, status);
- if (U_FAILURE(status)) {
- return;
- }
- getCharPtr()[position] = 0;
- getFieldPtr()[position] = kUndefinedField;
- fLength--;
-}
-
-int32_t FormattedStringBuilder::prepareForInsert(int32_t index, int32_t count, UErrorCode &status) {
- U_ASSERT(index >= 0);
- U_ASSERT(index <= fLength);
- U_ASSERT(count >= 0);
- if (index == 0 && fZero - count >= 0) {
- // Append to start
- fZero -= count;
- fLength += count;
- return fZero;
- } else if (index == fLength && fZero + fLength + count < getCapacity()) {
- // Append to end
- fLength += count;
- return fZero + fLength - count;
- } else {
- // Move chars around and/or allocate more space
- return prepareForInsertHelper(index, count, status);
- }
-}
-
-int32_t FormattedStringBuilder::prepareForInsertHelper(int32_t index, int32_t count, UErrorCode &status) {
- int32_t oldCapacity = getCapacity();
- int32_t oldZero = fZero;
- char16_t *oldChars = getCharPtr();
- Field *oldFields = getFieldPtr();
- if (fLength + count > oldCapacity) {
- int32_t newCapacity = (fLength + count) * 2;
- int32_t newZero = newCapacity / 2 - (fLength + count) / 2;
-
- // C++ note: malloc appears in two places: here and in the assignment operator.
- auto newChars = static_cast<char16_t *> (uprv_malloc(sizeof(char16_t) * newCapacity));
- auto newFields = static_cast<Field *>(uprv_malloc(sizeof(Field) * newCapacity));
- if (newChars == nullptr || newFields == nullptr) {
- uprv_free(newChars);
- uprv_free(newFields);
- status = U_MEMORY_ALLOCATION_ERROR;
- return -1;
- }
-
- // First copy the prefix and then the suffix, leaving room for the new chars that the
- // caller wants to insert.
- // C++ note: memcpy is OK because the src and dest do not overlap.
- uprv_memcpy2(newChars + newZero, oldChars + oldZero, sizeof(char16_t) * index);
- uprv_memcpy2(newChars + newZero + index + count,
- oldChars + oldZero + index,
- sizeof(char16_t) * (fLength - index));
- uprv_memcpy2(newFields + newZero, oldFields + oldZero, sizeof(Field) * index);
- uprv_memcpy2(newFields + newZero + index + count,
- oldFields + oldZero + index,
- sizeof(Field) * (fLength - index));
-
- if (fUsingHeap) {
- uprv_free(oldChars);
- uprv_free(oldFields);
- }
- fUsingHeap = true;
- fChars.heap.ptr = newChars;
- fChars.heap.capacity = newCapacity;
- fFields.heap.ptr = newFields;
- fFields.heap.capacity = newCapacity;
- fZero = newZero;
- fLength += count;
- } else {
- int32_t newZero = oldCapacity / 2 - (fLength + count) / 2;
-
- // C++ note: memmove is required because src and dest may overlap.
- // First copy the entire string to the location of the prefix, and then move the suffix
- // to make room for the new chars that the caller wants to insert.
- uprv_memmove2(oldChars + newZero, oldChars + oldZero, sizeof(char16_t) * fLength);
- uprv_memmove2(oldChars + newZero + index + count,
- oldChars + newZero + index,
- sizeof(char16_t) * (fLength - index));
- uprv_memmove2(oldFields + newZero, oldFields + oldZero, sizeof(Field) * fLength);
- uprv_memmove2(oldFields + newZero + index + count,
- oldFields + newZero + index,
- sizeof(Field) * (fLength - index));
-
- fZero = newZero;
- fLength += count;
- }
- return fZero + index;
-}
-
-int32_t FormattedStringBuilder::remove(int32_t index, int32_t count) {
- // TODO: Reset the heap here? (If the string after removal can fit on stack?)
- int32_t position = index + fZero;
- uprv_memmove2(getCharPtr() + position,
- getCharPtr() + position + count,
- sizeof(char16_t) * (fLength - index - count));
- uprv_memmove2(getFieldPtr() + position,
- getFieldPtr() + position + count,
- sizeof(Field) * (fLength - index - count));
- fLength -= count;
- return position;
-}
-
-UnicodeString FormattedStringBuilder::toUnicodeString() const {
- return UnicodeString(getCharPtr() + fZero, fLength);
-}
-
-const UnicodeString FormattedStringBuilder::toTempUnicodeString() const {
- // Readonly-alias constructor:
- return UnicodeString(FALSE, getCharPtr() + fZero, fLength);
-}
-
-UnicodeString FormattedStringBuilder::toDebugString() const {
- UnicodeString sb;
- sb.append(u"<FormattedStringBuilder [", -1);
- sb.append(toUnicodeString());
- sb.append(u"] [", -1);
- for (int i = 0; i < fLength; i++) {
- if (fieldAt(i) == kUndefinedField) {
- sb.append(u'n');
- } else if (fieldAt(i).getCategory() == UFIELD_CATEGORY_NUMBER) {
- char16_t c;
- switch (fieldAt(i).getField()) {
- case UNUM_SIGN_FIELD:
- c = u'-';
- break;
- case UNUM_INTEGER_FIELD:
- c = u'i';
- break;
- case UNUM_FRACTION_FIELD:
- c = u'f';
- break;
- case UNUM_EXPONENT_FIELD:
- c = u'e';
- break;
- case UNUM_EXPONENT_SIGN_FIELD:
- c = u'+';
- break;
- case UNUM_EXPONENT_SYMBOL_FIELD:
- c = u'E';
- break;
- case UNUM_DECIMAL_SEPARATOR_FIELD:
- c = u'.';
- break;
- case UNUM_GROUPING_SEPARATOR_FIELD:
- c = u',';
- break;
- case UNUM_PERCENT_FIELD:
- c = u'%';
- break;
- case UNUM_PERMILL_FIELD:
- c = u'‰';
- break;
- case UNUM_CURRENCY_FIELD:
- c = u'$';
- break;
- default:
- c = u'0' + fieldAt(i).getField();
- break;
- }
- sb.append(c);
- } else {
- sb.append(u'0' + fieldAt(i).getCategory());
- }
- }
- sb.append(u"]>", -1);
- return sb;
-}
-
-const char16_t *FormattedStringBuilder::chars() const {
- return getCharPtr() + fZero;
-}
-
-bool FormattedStringBuilder::contentEquals(const FormattedStringBuilder &other) const {
- if (fLength != other.fLength) {
- return false;
- }
- for (int32_t i = 0; i < fLength; i++) {
- if (charAt(i) != other.charAt(i) || fieldAt(i) != other.fieldAt(i)) {
- return false;
- }
- }
- return true;
-}
-
-bool FormattedStringBuilder::containsField(Field field) const {
- for (int32_t i = 0; i < fLength; i++) {
- if (field == fieldAt(i)) {
- return true;
- }
- }
- return false;
-}
-
-U_NAMESPACE_END
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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
+
+#include "formatted_string_builder.h"
+#include "unicode/ustring.h"
+#include "unicode/utf16.h"
+#include "unicode/unum.h" // for UNumberFormatFields literals
+
+namespace {
+
+// A version of uprv_memcpy that checks for length 0.
+// By default, uprv_memcpy requires a length of at least 1.
+inline void uprv_memcpy2(void* dest, const void* src, size_t len) {
+ if (len > 0) {
+ uprv_memcpy(dest, src, len);
+ }
+}
+
+// A version of uprv_memmove that checks for length 0.
+// By default, uprv_memmove requires a length of at least 1.
+inline void uprv_memmove2(void* dest, const void* src, size_t len) {
+ if (len > 0) {
+ uprv_memmove(dest, src, len);
+ }
+}
+
+} // namespace
+
+
+U_NAMESPACE_BEGIN
+
+FormattedStringBuilder::FormattedStringBuilder() {
+#if U_DEBUG
+ // Initializing the memory to non-zero helps catch some bugs that involve
+ // reading from an improperly terminated string.
+ for (int32_t i=0; i<getCapacity(); i++) {
+ getCharPtr()[i] = 1;
+ }
+#endif
+}
+
+FormattedStringBuilder::~FormattedStringBuilder() {
+ if (fUsingHeap) {
+ uprv_free(fChars.heap.ptr);
+ uprv_free(fFields.heap.ptr);
+ }
+}
+
+FormattedStringBuilder::FormattedStringBuilder(const FormattedStringBuilder &other) {
+ *this = other;
+}
+
+FormattedStringBuilder &FormattedStringBuilder::operator=(const FormattedStringBuilder &other) {
+ // Check for self-assignment
+ if (this == &other) {
+ return *this;
+ }
+
+ // Continue with deallocation and copying
+ if (fUsingHeap) {
+ uprv_free(fChars.heap.ptr);
+ uprv_free(fFields.heap.ptr);
+ fUsingHeap = false;
+ }
+
+ int32_t capacity = other.getCapacity();
+ if (capacity > DEFAULT_CAPACITY) {
+ // FIXME: uprv_malloc
+ // C++ note: malloc appears in two places: here and in prepareForInsertHelper.
+ auto newChars = static_cast<char16_t *> (uprv_malloc(sizeof(char16_t) * capacity));
+ auto newFields = static_cast<Field *>(uprv_malloc(sizeof(Field) * capacity));
+ if (newChars == nullptr || newFields == nullptr) {
+ // UErrorCode is not available; fail silently.
+ uprv_free(newChars);
+ uprv_free(newFields);
+ *this = FormattedStringBuilder(); // can't fail
+ return *this;
+ }
+
+ fUsingHeap = true;
+ fChars.heap.capacity = capacity;
+ fChars.heap.ptr = newChars;
+ fFields.heap.capacity = capacity;
+ fFields.heap.ptr = newFields;
+ }
+
+ uprv_memcpy2(getCharPtr(), other.getCharPtr(), sizeof(char16_t) * capacity);
+ uprv_memcpy2(getFieldPtr(), other.getFieldPtr(), sizeof(Field) * capacity);
+
+ fZero = other.fZero;
+ fLength = other.fLength;
+ return *this;
+}
+
+int32_t FormattedStringBuilder::length() const {
+ return fLength;
+}
+
+int32_t FormattedStringBuilder::codePointCount() const {
+ return u_countChar32(getCharPtr() + fZero, fLength);
+}
+
+UChar32 FormattedStringBuilder::getFirstCodePoint() const {
+ if (fLength == 0) {
+ return -1;
+ }
+ UChar32 cp;
+ U16_GET(getCharPtr() + fZero, 0, 0, fLength, cp);
+ return cp;
+}
+
+UChar32 FormattedStringBuilder::getLastCodePoint() const {
+ if (fLength == 0) {
+ return -1;
+ }
+ int32_t offset = fLength;
+ U16_BACK_1(getCharPtr() + fZero, 0, offset);
+ UChar32 cp;
+ U16_GET(getCharPtr() + fZero, 0, offset, fLength, cp);
+ return cp;
+}
+
+UChar32 FormattedStringBuilder::codePointAt(int32_t index) const {
+ UChar32 cp;
+ U16_GET(getCharPtr() + fZero, 0, index, fLength, cp);
+ return cp;
+}
+
+UChar32 FormattedStringBuilder::codePointBefore(int32_t index) const {
+ int32_t offset = index;
+ U16_BACK_1(getCharPtr() + fZero, 0, offset);
+ UChar32 cp;
+ U16_GET(getCharPtr() + fZero, 0, offset, fLength, cp);
+ return cp;
+}
+
+FormattedStringBuilder &FormattedStringBuilder::clear() {
+ // TODO: Reset the heap here?
+ fZero = getCapacity() / 2;
+ fLength = 0;
+ return *this;
+}
+
+int32_t
+FormattedStringBuilder::insertCodePoint(int32_t index, UChar32 codePoint, Field field, UErrorCode &status) {
+ int32_t count = U16_LENGTH(codePoint);
+ int32_t position = prepareForInsert(index, count, status);
+ if (U_FAILURE(status)) {
+ return count;
+ }
+ if (count == 1) {
+ getCharPtr()[position] = (char16_t) codePoint;
+ getFieldPtr()[position] = field;
+ } else {
+ getCharPtr()[position] = U16_LEAD(codePoint);
+ getCharPtr()[position + 1] = U16_TRAIL(codePoint);
+ getFieldPtr()[position] = getFieldPtr()[position + 1] = field;
+ }
+ return count;
+}
+
+int32_t FormattedStringBuilder::insert(int32_t index, const UnicodeString &unistr, Field field,
+ UErrorCode &status) {
+ if (unistr.length() == 0) {
+ // Nothing to insert.
+ return 0;
+ } else if (unistr.length() == 1) {
+ // Fast path: insert using insertCodePoint.
+ return insertCodePoint(index, unistr.charAt(0), field, status);
+ } else {
+ return insert(index, unistr, 0, unistr.length(), field, status);
+ }
+}
+
+int32_t
+FormattedStringBuilder::insert(int32_t index, const UnicodeString &unistr, int32_t start, int32_t end,
+ Field field, UErrorCode &status) {
+ int32_t count = end - start;
+ int32_t position = prepareForInsert(index, count, status);
+ if (U_FAILURE(status)) {
+ return count;
+ }
+ for (int32_t i = 0; i < count; i++) {
+ getCharPtr()[position + i] = unistr.charAt(start + i);
+ getFieldPtr()[position + i] = field;
+ }
+ return count;
+}
+
+int32_t
+FormattedStringBuilder::splice(int32_t startThis, int32_t endThis, const UnicodeString &unistr,
+ int32_t startOther, int32_t endOther, Field field, UErrorCode& status) {
+ int32_t thisLength = endThis - startThis;
+ int32_t otherLength = endOther - startOther;
+ int32_t count = otherLength - thisLength;
+ int32_t position;
+ if (count > 0) {
+ // Overall, chars need to be added.
+ position = prepareForInsert(startThis, count, status);
+ } else {
+ // Overall, chars need to be removed or kept the same.
+ position = remove(startThis, -count);
+ }
+ if (U_FAILURE(status)) {
+ return count;
+ }
+ for (int32_t i = 0; i < otherLength; i++) {
+ getCharPtr()[position + i] = unistr.charAt(startOther + i);
+ getFieldPtr()[position + i] = field;
+ }
+ return count;
+}
+
+int32_t FormattedStringBuilder::append(const FormattedStringBuilder &other, UErrorCode &status) {
+ return insert(fLength, other, status);
+}
+
+int32_t
+FormattedStringBuilder::insert(int32_t index, const FormattedStringBuilder &other, UErrorCode &status) {
+ if (this == &other) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ int32_t count = other.fLength;
+ if (count == 0) {
+ // Nothing to insert.
+ return 0;
+ }
+ int32_t position = prepareForInsert(index, count, status);
+ if (U_FAILURE(status)) {
+ return count;
+ }
+ for (int32_t i = 0; i < count; i++) {
+ getCharPtr()[position + i] = other.charAt(i);
+ getFieldPtr()[position + i] = other.fieldAt(i);
+ }
+ return count;
+}
+
+void FormattedStringBuilder::writeTerminator(UErrorCode& status) {
+ int32_t position = prepareForInsert(fLength, 1, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ getCharPtr()[position] = 0;
+ getFieldPtr()[position] = kUndefinedField;
+ fLength--;
+}
+
+int32_t FormattedStringBuilder::prepareForInsert(int32_t index, int32_t count, UErrorCode &status) {
+ U_ASSERT(index >= 0);
+ U_ASSERT(index <= fLength);
+ U_ASSERT(count >= 0);
+ if (index == 0 && fZero - count >= 0) {
+ // Append to start
+ fZero -= count;
+ fLength += count;
+ return fZero;
+ } else if (index == fLength && fZero + fLength + count < getCapacity()) {
+ // Append to end
+ fLength += count;
+ return fZero + fLength - count;
+ } else {
+ // Move chars around and/or allocate more space
+ return prepareForInsertHelper(index, count, status);
+ }
+}
+
+int32_t FormattedStringBuilder::prepareForInsertHelper(int32_t index, int32_t count, UErrorCode &status) {
+ int32_t oldCapacity = getCapacity();
+ int32_t oldZero = fZero;
+ char16_t *oldChars = getCharPtr();
+ Field *oldFields = getFieldPtr();
+ if (fLength + count > oldCapacity) {
+ int32_t newCapacity = (fLength + count) * 2;
+ int32_t newZero = newCapacity / 2 - (fLength + count) / 2;
+
+ // C++ note: malloc appears in two places: here and in the assignment operator.
+ auto newChars = static_cast<char16_t *> (uprv_malloc(sizeof(char16_t) * newCapacity));
+ auto newFields = static_cast<Field *>(uprv_malloc(sizeof(Field) * newCapacity));
+ if (newChars == nullptr || newFields == nullptr) {
+ uprv_free(newChars);
+ uprv_free(newFields);
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return -1;
+ }
+
+ // First copy the prefix and then the suffix, leaving room for the new chars that the
+ // caller wants to insert.
+ // C++ note: memcpy is OK because the src and dest do not overlap.
+ uprv_memcpy2(newChars + newZero, oldChars + oldZero, sizeof(char16_t) * index);
+ uprv_memcpy2(newChars + newZero + index + count,
+ oldChars + oldZero + index,
+ sizeof(char16_t) * (fLength - index));
+ uprv_memcpy2(newFields + newZero, oldFields + oldZero, sizeof(Field) * index);
+ uprv_memcpy2(newFields + newZero + index + count,
+ oldFields + oldZero + index,
+ sizeof(Field) * (fLength - index));
+
+ if (fUsingHeap) {
+ uprv_free(oldChars);
+ uprv_free(oldFields);
+ }
+ fUsingHeap = true;
+ fChars.heap.ptr = newChars;
+ fChars.heap.capacity = newCapacity;
+ fFields.heap.ptr = newFields;
+ fFields.heap.capacity = newCapacity;
+ fZero = newZero;
+ fLength += count;
+ } else {
+ int32_t newZero = oldCapacity / 2 - (fLength + count) / 2;
+
+ // C++ note: memmove is required because src and dest may overlap.
+ // First copy the entire string to the location of the prefix, and then move the suffix
+ // to make room for the new chars that the caller wants to insert.
+ uprv_memmove2(oldChars + newZero, oldChars + oldZero, sizeof(char16_t) * fLength);
+ uprv_memmove2(oldChars + newZero + index + count,
+ oldChars + newZero + index,
+ sizeof(char16_t) * (fLength - index));
+ uprv_memmove2(oldFields + newZero, oldFields + oldZero, sizeof(Field) * fLength);
+ uprv_memmove2(oldFields + newZero + index + count,
+ oldFields + newZero + index,
+ sizeof(Field) * (fLength - index));
+
+ fZero = newZero;
+ fLength += count;
+ }
+ return fZero + index;
+}
+
+int32_t FormattedStringBuilder::remove(int32_t index, int32_t count) {
+ // TODO: Reset the heap here? (If the string after removal can fit on stack?)
+ int32_t position = index + fZero;
+ uprv_memmove2(getCharPtr() + position,
+ getCharPtr() + position + count,
+ sizeof(char16_t) * (fLength - index - count));
+ uprv_memmove2(getFieldPtr() + position,
+ getFieldPtr() + position + count,
+ sizeof(Field) * (fLength - index - count));
+ fLength -= count;
+ return position;
+}
+
+UnicodeString FormattedStringBuilder::toUnicodeString() const {
+ return UnicodeString(getCharPtr() + fZero, fLength);
+}
+
+const UnicodeString FormattedStringBuilder::toTempUnicodeString() const {
+ // Readonly-alias constructor:
+ return UnicodeString(FALSE, getCharPtr() + fZero, fLength);
+}
+
+UnicodeString FormattedStringBuilder::toDebugString() const {
+ UnicodeString sb;
+ sb.append(u"<FormattedStringBuilder [", -1);
+ sb.append(toUnicodeString());
+ sb.append(u"] [", -1);
+ for (int i = 0; i < fLength; i++) {
+ if (fieldAt(i) == kUndefinedField) {
+ sb.append(u'n');
+ } else if (fieldAt(i).getCategory() == UFIELD_CATEGORY_NUMBER) {
+ char16_t c;
+ switch (fieldAt(i).getField()) {
+ case UNUM_SIGN_FIELD:
+ c = u'-';
+ break;
+ case UNUM_INTEGER_FIELD:
+ c = u'i';
+ break;
+ case UNUM_FRACTION_FIELD:
+ c = u'f';
+ break;
+ case UNUM_EXPONENT_FIELD:
+ c = u'e';
+ break;
+ case UNUM_EXPONENT_SIGN_FIELD:
+ c = u'+';
+ break;
+ case UNUM_EXPONENT_SYMBOL_FIELD:
+ c = u'E';
+ break;
+ case UNUM_DECIMAL_SEPARATOR_FIELD:
+ c = u'.';
+ break;
+ case UNUM_GROUPING_SEPARATOR_FIELD:
+ c = u',';
+ break;
+ case UNUM_PERCENT_FIELD:
+ c = u'%';
+ break;
+ case UNUM_PERMILL_FIELD:
+ c = u'‰';
+ break;
+ case UNUM_CURRENCY_FIELD:
+ c = u'$';
+ break;
+ default:
+ c = u'0' + fieldAt(i).getField();
+ break;
+ }
+ sb.append(c);
+ } else {
+ sb.append(u'0' + fieldAt(i).getCategory());
+ }
+ }
+ sb.append(u"]>", -1);
+ return sb;
+}
+
+const char16_t *FormattedStringBuilder::chars() const {
+ return getCharPtr() + fZero;
+}
+
+bool FormattedStringBuilder::contentEquals(const FormattedStringBuilder &other) const {
+ if (fLength != other.fLength) {
+ return false;
+ }
+ for (int32_t i = 0; i < fLength; i++) {
+ if (charAt(i) != other.charAt(i) || fieldAt(i) != other.fieldAt(i)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool FormattedStringBuilder::containsField(Field field) const {
+ for (int32_t i = 0; i < fLength; i++) {
+ if (field == fieldAt(i)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/formatted_string_builder.h b/contrib/libs/icu/i18n/formatted_string_builder.h
index 4567dc1d66..87d7dc9ad8 100644
--- a/contrib/libs/icu/i18n/formatted_string_builder.h
+++ b/contrib/libs/icu/i18n/formatted_string_builder.h
@@ -1,271 +1,271 @@
-// © 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_STRINGBUILDER_H__
-#define __NUMBER_STRINGBUILDER_H__
-
-
-#include <cstdint>
-#include <type_traits>
-
-#include "cstring.h"
-#include "uassert.h"
-#include "fphdlimp.h"
-
-U_NAMESPACE_BEGIN
-
-class FormattedValueStringBuilderImpl;
-
-/**
- * A StringBuilder optimized for formatting. It implements the following key
- * features beyond a UnicodeString:
- *
- * <ol>
- * <li>Efficient prepend as well as append.
- * <li>Keeps tracks of Fields in an efficient manner.
- * </ol>
- *
- * See also FormattedValueStringBuilderImpl.
- *
- * @author sffc (Shane Carr)
- */
-class U_I18N_API FormattedStringBuilder : public UMemory {
- private:
- static const int32_t DEFAULT_CAPACITY = 40;
-
- template<typename T>
- union ValueOrHeapArray {
- T value[DEFAULT_CAPACITY];
- struct {
- T *ptr;
- int32_t capacity;
- } heap;
- };
-
- public:
- FormattedStringBuilder();
-
- ~FormattedStringBuilder();
-
- FormattedStringBuilder(const FormattedStringBuilder &other);
-
- // Convention: bottom 4 bits for field, top 4 bits for field category.
- // Field category 0 implies the number category so that the number field
- // literals can be directly passed as a Field type.
- // See the helper functions in "StringBuilderFieldUtils" below.
- // Exported as U_I18N_API so it can be used by other exports on Windows.
- struct U_I18N_API Field {
- uint8_t bits;
-
- Field() = default;
- constexpr Field(uint8_t category, uint8_t field);
-
- inline UFieldCategory getCategory() const;
- inline int32_t getField() const;
- inline bool isNumeric() const;
- inline bool isUndefined() const;
- inline bool operator==(const Field& other) const;
- inline bool operator!=(const Field& other) const;
- };
-
- FormattedStringBuilder &operator=(const FormattedStringBuilder &other);
-
- int32_t length() const;
-
- int32_t codePointCount() const;
-
- inline char16_t charAt(int32_t index) const {
- U_ASSERT(index >= 0);
- U_ASSERT(index < fLength);
- return getCharPtr()[fZero + index];
- }
-
- inline Field fieldAt(int32_t index) const {
- U_ASSERT(index >= 0);
- U_ASSERT(index < fLength);
- return getFieldPtr()[fZero + index];
- }
-
- UChar32 getFirstCodePoint() const;
-
- UChar32 getLastCodePoint() const;
-
- UChar32 codePointAt(int32_t index) const;
-
- UChar32 codePointBefore(int32_t index) const;
-
- FormattedStringBuilder &clear();
-
- /** Appends a UTF-16 code unit. */
- inline int32_t appendChar16(char16_t codeUnit, Field field, UErrorCode& status) {
- // appendCodePoint handles both code units and code points.
- return insertCodePoint(fLength, codeUnit, field, status);
- }
-
- /** Inserts a UTF-16 code unit. Note: insert at index 0 is very efficient. */
- inline int32_t insertChar16(int32_t index, char16_t codeUnit, Field field, UErrorCode& status) {
- // insertCodePoint handles both code units and code points.
- return insertCodePoint(index, codeUnit, field, status);
- }
-
- /** Appends a Unicode code point. */
- inline int32_t appendCodePoint(UChar32 codePoint, Field field, UErrorCode &status) {
- return insertCodePoint(fLength, codePoint, field, status);
- }
-
- /** Inserts a Unicode code point. Note: insert at index 0 is very efficient. */
- int32_t insertCodePoint(int32_t index, UChar32 codePoint, Field field, UErrorCode &status);
-
- /** Appends a string. */
- inline int32_t append(const UnicodeString &unistr, Field field, UErrorCode &status) {
- return insert(fLength, unistr, field, status);
- }
-
- /** Inserts a string. Note: insert at index 0 is very efficient. */
- int32_t insert(int32_t index, const UnicodeString &unistr, Field field, UErrorCode &status);
-
- /** Inserts a substring. Note: insert at index 0 is very efficient.
- *
- * @param start Start index of the substring of unistr to be inserted.
- * @param end End index of the substring of unistr to be inserted (exclusive).
- */
- int32_t insert(int32_t index, const UnicodeString &unistr, int32_t start, int32_t end, Field field,
- UErrorCode &status);
-
- /** Deletes a substring and then inserts a string at that same position.
- * Similar to JavaScript Array.prototype.splice().
- *
- * @param startThis Start of the span to delete.
- * @param endThis End of the span to delete (exclusive).
- * @param unistr The string to insert at the deletion position.
- * @param startOther Start index of the substring of unistr to be inserted.
- * @param endOther End index of the substring of unistr to be inserted (exclusive).
- */
- int32_t splice(int32_t startThis, int32_t endThis, const UnicodeString &unistr,
- int32_t startOther, int32_t endOther, Field field, UErrorCode& status);
-
- /** Appends a formatted string. */
- int32_t append(const FormattedStringBuilder &other, UErrorCode &status);
-
- /** Inserts a formatted string. Note: insert at index 0 is very efficient. */
- int32_t insert(int32_t index, const FormattedStringBuilder &other, UErrorCode &status);
-
- /**
- * Ensures that the string buffer contains a NUL terminator. The NUL terminator does
- * not count toward the string length. Any further changes to the string (insert or
- * append) may invalidate the NUL terminator.
- *
- * You should call this method after the formatted string is completely built if you
- * plan to return a pointer to the string from a C API.
- */
- void writeTerminator(UErrorCode& status);
-
- /**
- * Gets a "safe" UnicodeString that can be used even after the FormattedStringBuilder is destructed.
- */
- UnicodeString toUnicodeString() const;
-
- /**
- * Gets an "unsafe" UnicodeString that is valid only as long as the FormattedStringBuilder is alive and
- * unchanged. Slightly faster than toUnicodeString().
- */
- const UnicodeString toTempUnicodeString() const;
-
- UnicodeString toDebugString() const;
-
- const char16_t *chars() const;
-
- bool contentEquals(const FormattedStringBuilder &other) const;
-
- bool containsField(Field field) const;
-
- private:
- bool fUsingHeap = false;
- ValueOrHeapArray<char16_t> fChars;
- ValueOrHeapArray<Field> fFields;
- int32_t fZero = DEFAULT_CAPACITY / 2;
- int32_t fLength = 0;
-
- inline char16_t *getCharPtr() {
- return fUsingHeap ? fChars.heap.ptr : fChars.value;
- }
-
- inline const char16_t *getCharPtr() const {
- return fUsingHeap ? fChars.heap.ptr : fChars.value;
- }
-
- inline Field *getFieldPtr() {
- return fUsingHeap ? fFields.heap.ptr : fFields.value;
- }
-
- inline const Field *getFieldPtr() const {
- return fUsingHeap ? fFields.heap.ptr : fFields.value;
- }
-
- inline int32_t getCapacity() const {
- return fUsingHeap ? fChars.heap.capacity : DEFAULT_CAPACITY;
- }
-
- int32_t prepareForInsert(int32_t index, int32_t count, UErrorCode &status);
-
- int32_t prepareForInsertHelper(int32_t index, int32_t count, UErrorCode &status);
-
- int32_t remove(int32_t index, int32_t count);
-
- friend class FormattedValueStringBuilderImpl;
-};
-
-static_assert(
- std::is_pod<FormattedStringBuilder::Field>::value,
- "Field should be a POD type for efficient initialization");
-
-constexpr FormattedStringBuilder::Field::Field(uint8_t category, uint8_t field)
- : bits((
- U_ASSERT(category <= 0xf),
- U_ASSERT(field <= 0xf),
- static_cast<uint8_t>((category << 4) | field)
- )) {}
-
-/**
- * Internal constant for the undefined field for use in FormattedStringBuilder.
- */
-constexpr FormattedStringBuilder::Field kUndefinedField = {UFIELD_CATEGORY_UNDEFINED, 0};
-
-/**
- * Internal field to signal "numeric" when fields are not supported in NumberFormat.
- */
-constexpr FormattedStringBuilder::Field kGeneralNumericField = {UFIELD_CATEGORY_UNDEFINED, 1};
-
-inline UFieldCategory FormattedStringBuilder::Field::getCategory() const {
- return static_cast<UFieldCategory>(bits >> 4);
-}
-
-inline int32_t FormattedStringBuilder::Field::getField() const {
- return bits & 0xf;
-}
-
-inline bool FormattedStringBuilder::Field::isNumeric() const {
- return getCategory() == UFIELD_CATEGORY_NUMBER || *this == kGeneralNumericField;
-}
-
-inline bool FormattedStringBuilder::Field::isUndefined() const {
- return getCategory() == UFIELD_CATEGORY_UNDEFINED;
-}
-
-inline bool FormattedStringBuilder::Field::operator==(const Field& other) const {
- return bits == other.bits;
-}
-
-inline bool FormattedStringBuilder::Field::operator!=(const Field& other) const {
- return bits != other.bits;
-}
-
-U_NAMESPACE_END
-
-
-#endif //__NUMBER_STRINGBUILDER_H__
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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_STRINGBUILDER_H__
+#define __NUMBER_STRINGBUILDER_H__
+
+
+#include <cstdint>
+#include <type_traits>
+
+#include "cstring.h"
+#include "uassert.h"
+#include "fphdlimp.h"
+
+U_NAMESPACE_BEGIN
+
+class FormattedValueStringBuilderImpl;
+
+/**
+ * A StringBuilder optimized for formatting. It implements the following key
+ * features beyond a UnicodeString:
+ *
+ * <ol>
+ * <li>Efficient prepend as well as append.
+ * <li>Keeps tracks of Fields in an efficient manner.
+ * </ol>
+ *
+ * See also FormattedValueStringBuilderImpl.
+ *
+ * @author sffc (Shane Carr)
+ */
+class U_I18N_API FormattedStringBuilder : public UMemory {
+ private:
+ static const int32_t DEFAULT_CAPACITY = 40;
+
+ template<typename T>
+ union ValueOrHeapArray {
+ T value[DEFAULT_CAPACITY];
+ struct {
+ T *ptr;
+ int32_t capacity;
+ } heap;
+ };
+
+ public:
+ FormattedStringBuilder();
+
+ ~FormattedStringBuilder();
+
+ FormattedStringBuilder(const FormattedStringBuilder &other);
+
+ // Convention: bottom 4 bits for field, top 4 bits for field category.
+ // Field category 0 implies the number category so that the number field
+ // literals can be directly passed as a Field type.
+ // See the helper functions in "StringBuilderFieldUtils" below.
+ // Exported as U_I18N_API so it can be used by other exports on Windows.
+ struct U_I18N_API Field {
+ uint8_t bits;
+
+ Field() = default;
+ constexpr Field(uint8_t category, uint8_t field);
+
+ inline UFieldCategory getCategory() const;
+ inline int32_t getField() const;
+ inline bool isNumeric() const;
+ inline bool isUndefined() const;
+ inline bool operator==(const Field& other) const;
+ inline bool operator!=(const Field& other) const;
+ };
+
+ FormattedStringBuilder &operator=(const FormattedStringBuilder &other);
+
+ int32_t length() const;
+
+ int32_t codePointCount() const;
+
+ inline char16_t charAt(int32_t index) const {
+ U_ASSERT(index >= 0);
+ U_ASSERT(index < fLength);
+ return getCharPtr()[fZero + index];
+ }
+
+ inline Field fieldAt(int32_t index) const {
+ U_ASSERT(index >= 0);
+ U_ASSERT(index < fLength);
+ return getFieldPtr()[fZero + index];
+ }
+
+ UChar32 getFirstCodePoint() const;
+
+ UChar32 getLastCodePoint() const;
+
+ UChar32 codePointAt(int32_t index) const;
+
+ UChar32 codePointBefore(int32_t index) const;
+
+ FormattedStringBuilder &clear();
+
+ /** Appends a UTF-16 code unit. */
+ inline int32_t appendChar16(char16_t codeUnit, Field field, UErrorCode& status) {
+ // appendCodePoint handles both code units and code points.
+ return insertCodePoint(fLength, codeUnit, field, status);
+ }
+
+ /** Inserts a UTF-16 code unit. Note: insert at index 0 is very efficient. */
+ inline int32_t insertChar16(int32_t index, char16_t codeUnit, Field field, UErrorCode& status) {
+ // insertCodePoint handles both code units and code points.
+ return insertCodePoint(index, codeUnit, field, status);
+ }
+
+ /** Appends a Unicode code point. */
+ inline int32_t appendCodePoint(UChar32 codePoint, Field field, UErrorCode &status) {
+ return insertCodePoint(fLength, codePoint, field, status);
+ }
+
+ /** Inserts a Unicode code point. Note: insert at index 0 is very efficient. */
+ int32_t insertCodePoint(int32_t index, UChar32 codePoint, Field field, UErrorCode &status);
+
+ /** Appends a string. */
+ inline int32_t append(const UnicodeString &unistr, Field field, UErrorCode &status) {
+ return insert(fLength, unistr, field, status);
+ }
+
+ /** Inserts a string. Note: insert at index 0 is very efficient. */
+ int32_t insert(int32_t index, const UnicodeString &unistr, Field field, UErrorCode &status);
+
+ /** Inserts a substring. Note: insert at index 0 is very efficient.
+ *
+ * @param start Start index of the substring of unistr to be inserted.
+ * @param end End index of the substring of unistr to be inserted (exclusive).
+ */
+ int32_t insert(int32_t index, const UnicodeString &unistr, int32_t start, int32_t end, Field field,
+ UErrorCode &status);
+
+ /** Deletes a substring and then inserts a string at that same position.
+ * Similar to JavaScript Array.prototype.splice().
+ *
+ * @param startThis Start of the span to delete.
+ * @param endThis End of the span to delete (exclusive).
+ * @param unistr The string to insert at the deletion position.
+ * @param startOther Start index of the substring of unistr to be inserted.
+ * @param endOther End index of the substring of unistr to be inserted (exclusive).
+ */
+ int32_t splice(int32_t startThis, int32_t endThis, const UnicodeString &unistr,
+ int32_t startOther, int32_t endOther, Field field, UErrorCode& status);
+
+ /** Appends a formatted string. */
+ int32_t append(const FormattedStringBuilder &other, UErrorCode &status);
+
+ /** Inserts a formatted string. Note: insert at index 0 is very efficient. */
+ int32_t insert(int32_t index, const FormattedStringBuilder &other, UErrorCode &status);
+
+ /**
+ * Ensures that the string buffer contains a NUL terminator. The NUL terminator does
+ * not count toward the string length. Any further changes to the string (insert or
+ * append) may invalidate the NUL terminator.
+ *
+ * You should call this method after the formatted string is completely built if you
+ * plan to return a pointer to the string from a C API.
+ */
+ void writeTerminator(UErrorCode& status);
+
+ /**
+ * Gets a "safe" UnicodeString that can be used even after the FormattedStringBuilder is destructed.
+ */
+ UnicodeString toUnicodeString() const;
+
+ /**
+ * Gets an "unsafe" UnicodeString that is valid only as long as the FormattedStringBuilder is alive and
+ * unchanged. Slightly faster than toUnicodeString().
+ */
+ const UnicodeString toTempUnicodeString() const;
+
+ UnicodeString toDebugString() const;
+
+ const char16_t *chars() const;
+
+ bool contentEquals(const FormattedStringBuilder &other) const;
+
+ bool containsField(Field field) const;
+
+ private:
+ bool fUsingHeap = false;
+ ValueOrHeapArray<char16_t> fChars;
+ ValueOrHeapArray<Field> fFields;
+ int32_t fZero = DEFAULT_CAPACITY / 2;
+ int32_t fLength = 0;
+
+ inline char16_t *getCharPtr() {
+ return fUsingHeap ? fChars.heap.ptr : fChars.value;
+ }
+
+ inline const char16_t *getCharPtr() const {
+ return fUsingHeap ? fChars.heap.ptr : fChars.value;
+ }
+
+ inline Field *getFieldPtr() {
+ return fUsingHeap ? fFields.heap.ptr : fFields.value;
+ }
+
+ inline const Field *getFieldPtr() const {
+ return fUsingHeap ? fFields.heap.ptr : fFields.value;
+ }
+
+ inline int32_t getCapacity() const {
+ return fUsingHeap ? fChars.heap.capacity : DEFAULT_CAPACITY;
+ }
+
+ int32_t prepareForInsert(int32_t index, int32_t count, UErrorCode &status);
+
+ int32_t prepareForInsertHelper(int32_t index, int32_t count, UErrorCode &status);
+
+ int32_t remove(int32_t index, int32_t count);
+
+ friend class FormattedValueStringBuilderImpl;
+};
+
+static_assert(
+ std::is_pod<FormattedStringBuilder::Field>::value,
+ "Field should be a POD type for efficient initialization");
+
+constexpr FormattedStringBuilder::Field::Field(uint8_t category, uint8_t field)
+ : bits((
+ U_ASSERT(category <= 0xf),
+ U_ASSERT(field <= 0xf),
+ static_cast<uint8_t>((category << 4) | field)
+ )) {}
+
+/**
+ * Internal constant for the undefined field for use in FormattedStringBuilder.
+ */
+constexpr FormattedStringBuilder::Field kUndefinedField = {UFIELD_CATEGORY_UNDEFINED, 0};
+
+/**
+ * Internal field to signal "numeric" when fields are not supported in NumberFormat.
+ */
+constexpr FormattedStringBuilder::Field kGeneralNumericField = {UFIELD_CATEGORY_UNDEFINED, 1};
+
+inline UFieldCategory FormattedStringBuilder::Field::getCategory() const {
+ return static_cast<UFieldCategory>(bits >> 4);
+}
+
+inline int32_t FormattedStringBuilder::Field::getField() const {
+ return bits & 0xf;
+}
+
+inline bool FormattedStringBuilder::Field::isNumeric() const {
+ return getCategory() == UFIELD_CATEGORY_NUMBER || *this == kGeneralNumericField;
+}
+
+inline bool FormattedStringBuilder::Field::isUndefined() const {
+ return getCategory() == UFIELD_CATEGORY_UNDEFINED;
+}
+
+inline bool FormattedStringBuilder::Field::operator==(const Field& other) const {
+ return bits == other.bits;
+}
+
+inline bool FormattedStringBuilder::Field::operator!=(const Field& other) const {
+ return bits != other.bits;
+}
+
+U_NAMESPACE_END
+
+
+#endif //__NUMBER_STRINGBUILDER_H__
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/formattedval_impl.h b/contrib/libs/icu/i18n/formattedval_impl.h
index 7bee374286..883af8c581 100644
--- a/contrib/libs/icu/i18n/formattedval_impl.h
+++ b/contrib/libs/icu/i18n/formattedval_impl.h
@@ -1,277 +1,277 @@
-// © 2018 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html
-
-#ifndef __FORMVAL_IMPL_H__
-#define __FORMVAL_IMPL_H__
-
-#include "unicode/utypes.h"
-#if !UCONFIG_NO_FORMATTING
-
-// This file contains compliant implementations of FormattedValue which can be
-// leveraged by ICU formatters.
-//
-// Each implementation is defined in its own cpp file in order to split
-// dependencies more modularly.
-
-#include "unicode/formattedvalue.h"
-#include "capi_helper.h"
-#include "fphdlimp.h"
-#include "util.h"
-#include "uvectr32.h"
-#include "formatted_string_builder.h"
-
-
-/**
- * Represents the type of constraint for ConstrainedFieldPosition.
- *
- * Constraints are used to control the behavior of iteration in FormattedValue.
- *
- * @internal
- */
-typedef enum UCFPosConstraintType {
- /**
- * Represents the lack of a constraint.
- *
- * This is the value of fConstraint if no "constrain" methods were called.
- *
- * @internal
- */
- UCFPOS_CONSTRAINT_NONE = 0,
-
- /**
- * Represents that the field category is constrained.
- *
- * This is the value of fConstraint if constraintCategory was called.
- *
- * FormattedValue implementations should not change the field category
- * while this constraint is active.
- *
- * @internal
- */
- UCFPOS_CONSTRAINT_CATEGORY,
-
- /**
- * Represents that the field and field category are constrained.
- *
- * This is the value of fConstraint if constraintField was called.
- *
- * FormattedValue implementations should not change the field or field category
- * while this constraint is active.
- *
- * @internal
- */
- UCFPOS_CONSTRAINT_FIELD
-} UCFPosConstraintType;
-
-
-U_NAMESPACE_BEGIN
-
-
-/**
- * Implementation of FormattedValue using FieldPositionHandler to accept fields.
- */
-class FormattedValueFieldPositionIteratorImpl : public UMemory, public FormattedValue {
-public:
-
- /** @param initialFieldCapacity Initially allocate space for this many fields. */
- FormattedValueFieldPositionIteratorImpl(int32_t initialFieldCapacity, UErrorCode& status);
-
- virtual ~FormattedValueFieldPositionIteratorImpl();
-
- // Implementation of FormattedValue (const):
-
- UnicodeString toString(UErrorCode& status) const U_OVERRIDE;
- UnicodeString toTempString(UErrorCode& status) const U_OVERRIDE;
- Appendable& appendTo(Appendable& appendable, UErrorCode& status) const U_OVERRIDE;
- UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const U_OVERRIDE;
-
- // Additional methods used during construction phase only (non-const):
-
- FieldPositionIteratorHandler getHandler(UErrorCode& status);
- void appendString(UnicodeString string, UErrorCode& status);
-
- /**
- * Computes the spans for duplicated values.
- * For example, if the string has fields:
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#ifndef __FORMVAL_IMPL_H__
+#define __FORMVAL_IMPL_H__
+
+#include "unicode/utypes.h"
+#if !UCONFIG_NO_FORMATTING
+
+// This file contains compliant implementations of FormattedValue which can be
+// leveraged by ICU formatters.
+//
+// Each implementation is defined in its own cpp file in order to split
+// dependencies more modularly.
+
+#include "unicode/formattedvalue.h"
+#include "capi_helper.h"
+#include "fphdlimp.h"
+#include "util.h"
+#include "uvectr32.h"
+#include "formatted_string_builder.h"
+
+
+/**
+ * Represents the type of constraint for ConstrainedFieldPosition.
+ *
+ * Constraints are used to control the behavior of iteration in FormattedValue.
+ *
+ * @internal
+ */
+typedef enum UCFPosConstraintType {
+ /**
+ * Represents the lack of a constraint.
*
- * ...aa..[b.cc]..d.[bb.e.c]..a..
- *
- * then the spans will be the bracketed regions.
- *
- * Assumes that the currently known fields are sorted
- * and all in the same category.
- */
- void addOverlapSpans(UFieldCategory spanCategory, int8_t firstIndex, UErrorCode& status);
-
- /**
- * Sorts the fields: start index first, length second.
- */
- void sort();
-
-private:
- UnicodeString fString;
- UVector32 fFields;
-};
-
-
-/**
- * Implementation of FormattedValue based on FormattedStringBuilder.
- *
- * The implementation currently revolves around numbers and number fields.
- * However, it can be generalized in the future when there is a need.
- *
- * @author sffc (Shane Carr)
- */
-// Exported as U_I18N_API for tests
-class U_I18N_API FormattedValueStringBuilderImpl : public UMemory, public FormattedValue {
-public:
-
- FormattedValueStringBuilderImpl(FormattedStringBuilder::Field numericField);
-
- virtual ~FormattedValueStringBuilderImpl();
-
- // Implementation of FormattedValue (const):
-
- UnicodeString toString(UErrorCode& status) const U_OVERRIDE;
- UnicodeString toTempString(UErrorCode& status) const U_OVERRIDE;
- Appendable& appendTo(Appendable& appendable, UErrorCode& status) const U_OVERRIDE;
- UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const U_OVERRIDE;
-
- // Additional helper functions:
- UBool nextFieldPosition(FieldPosition& fp, UErrorCode& status) const;
- void getAllFieldPositions(FieldPositionIteratorHandler& fpih, UErrorCode& status) const;
- inline FormattedStringBuilder& getStringRef() {
- return fString;
- }
- inline const FormattedStringBuilder& getStringRef() const {
- return fString;
- }
-
-private:
- FormattedStringBuilder fString;
- FormattedStringBuilder::Field fNumericField;
-
- bool nextPositionImpl(ConstrainedFieldPosition& cfpos, FormattedStringBuilder::Field numericField, UErrorCode& status) const;
- static bool isIntOrGroup(FormattedStringBuilder::Field field);
- int32_t trimBack(int32_t limit) const;
- int32_t trimFront(int32_t start) const;
-};
-
-
-// C API Helpers for FormattedValue
-// Magic number as ASCII == "UFV"
-struct UFormattedValueImpl;
-typedef IcuCApiHelper<UFormattedValue, UFormattedValueImpl, 0x55465600> UFormattedValueApiHelper;
-struct UFormattedValueImpl : public UMemory, public UFormattedValueApiHelper {
- // This pointer should be set by the child class.
- FormattedValue* fFormattedValue = nullptr;
-};
-
-
-/** Boilerplate to check for valid status before dereferencing the fData pointer. */
-#define UPRV_FORMATTED_VALUE_METHOD_GUARD(returnExpression) \
- if (U_FAILURE(status)) { \
- return returnExpression; \
- } \
- if (fData == nullptr) { \
- status = fErrorCode; \
- return returnExpression; \
- } \
-
-
-/** Implementation of the methods from U_FORMATTED_VALUE_SUBCLASS_AUTO. */
-#define UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(Name) \
- Name::Name(Name&& src) U_NOEXCEPT \
- : fData(src.fData), fErrorCode(src.fErrorCode) { \
- src.fData = nullptr; \
- src.fErrorCode = U_INVALID_STATE_ERROR; \
- } \
- Name::~Name() { \
- delete fData; \
- fData = nullptr; \
- } \
- Name& Name::operator=(Name&& src) U_NOEXCEPT { \
- delete fData; \
- fData = src.fData; \
- src.fData = nullptr; \
- fErrorCode = src.fErrorCode; \
- src.fErrorCode = U_INVALID_STATE_ERROR; \
- return *this; \
- } \
- UnicodeString Name::toString(UErrorCode& status) const { \
- UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) \
- return fData->toString(status); \
- } \
- UnicodeString Name::toTempString(UErrorCode& status) const { \
- UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) \
- return fData->toTempString(status); \
- } \
- Appendable& Name::appendTo(Appendable& appendable, UErrorCode& status) const { \
- UPRV_FORMATTED_VALUE_METHOD_GUARD(appendable) \
- return fData->appendTo(appendable, status); \
- } \
- UBool Name::nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const { \
- UPRV_FORMATTED_VALUE_METHOD_GUARD(FALSE) \
- return fData->nextPosition(cfpos, status); \
- }
-
-
-/** Like UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL but without impl type declarations. */
-#define UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(CType, ImplType, HelperType, Prefix) \
- U_CAPI CType* U_EXPORT2 \
- Prefix ## _openResult (UErrorCode* ec) { \
- if (U_FAILURE(*ec)) { \
- return nullptr; \
- } \
- ImplType* impl = new ImplType(); \
- if (impl == nullptr) { \
- *ec = U_MEMORY_ALLOCATION_ERROR; \
- return nullptr; \
- } \
- return static_cast<HelperType*>(impl)->exportForC(); \
- } \
- U_DRAFT const UFormattedValue* U_EXPORT2 \
- Prefix ## _resultAsValue (const CType* uresult, UErrorCode* ec) { \
- const ImplType* result = HelperType::validate(uresult, *ec); \
- if (U_FAILURE(*ec)) { return nullptr; } \
- return static_cast<const UFormattedValueApiHelper*>(result)->exportConstForC(); \
- } \
- U_CAPI void U_EXPORT2 \
- Prefix ## _closeResult (CType* uresult) { \
- UErrorCode localStatus = U_ZERO_ERROR; \
- const ImplType* impl = HelperType::validate(uresult, localStatus); \
- delete impl; \
- }
-
-
-/**
- * Implementation of the standard methods for a UFormattedValue "subclass" C API.
- * @param CPPType The public C++ type, like FormattedList
- * @param CType The public C type, like UFormattedList
- * @param ImplType A name to use for the implementation class
- * @param HelperType A name to use for the "mixin" typedef for C API conversion
- * @param Prefix The C API prefix, like ulistfmt
- * @param MagicNumber A unique 32-bit number to use to identify this type
- */
-#define UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL(CPPType, CType, ImplType, HelperType, Prefix, MagicNumber) \
- U_NAMESPACE_BEGIN \
- class ImplType; \
- typedef IcuCApiHelper<CType, ImplType, MagicNumber> HelperType; \
- class ImplType : public UFormattedValueImpl, public HelperType { \
- public: \
- ImplType(); \
- ~ImplType(); \
- CPPType fImpl; \
- }; \
- ImplType::ImplType() { \
- fFormattedValue = &fImpl; \
- } \
- ImplType::~ImplType() {} \
- U_NAMESPACE_END \
- UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(CType, ImplType, HelperType, Prefix)
-
-
-U_NAMESPACE_END
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
-#endif // __FORMVAL_IMPL_H__
+ * This is the value of fConstraint if no "constrain" methods were called.
+ *
+ * @internal
+ */
+ UCFPOS_CONSTRAINT_NONE = 0,
+
+ /**
+ * Represents that the field category is constrained.
+ *
+ * This is the value of fConstraint if constraintCategory was called.
+ *
+ * FormattedValue implementations should not change the field category
+ * while this constraint is active.
+ *
+ * @internal
+ */
+ UCFPOS_CONSTRAINT_CATEGORY,
+
+ /**
+ * Represents that the field and field category are constrained.
+ *
+ * This is the value of fConstraint if constraintField was called.
+ *
+ * FormattedValue implementations should not change the field or field category
+ * while this constraint is active.
+ *
+ * @internal
+ */
+ UCFPOS_CONSTRAINT_FIELD
+} UCFPosConstraintType;
+
+
+U_NAMESPACE_BEGIN
+
+
+/**
+ * Implementation of FormattedValue using FieldPositionHandler to accept fields.
+ */
+class FormattedValueFieldPositionIteratorImpl : public UMemory, public FormattedValue {
+public:
+
+ /** @param initialFieldCapacity Initially allocate space for this many fields. */
+ FormattedValueFieldPositionIteratorImpl(int32_t initialFieldCapacity, UErrorCode& status);
+
+ virtual ~FormattedValueFieldPositionIteratorImpl();
+
+ // Implementation of FormattedValue (const):
+
+ UnicodeString toString(UErrorCode& status) const U_OVERRIDE;
+ UnicodeString toTempString(UErrorCode& status) const U_OVERRIDE;
+ Appendable& appendTo(Appendable& appendable, UErrorCode& status) const U_OVERRIDE;
+ UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const U_OVERRIDE;
+
+ // Additional methods used during construction phase only (non-const):
+
+ FieldPositionIteratorHandler getHandler(UErrorCode& status);
+ void appendString(UnicodeString string, UErrorCode& status);
+
+ /**
+ * Computes the spans for duplicated values.
+ * For example, if the string has fields:
+ *
+ * ...aa..[b.cc]..d.[bb.e.c]..a..
+ *
+ * then the spans will be the bracketed regions.
+ *
+ * Assumes that the currently known fields are sorted
+ * and all in the same category.
+ */
+ void addOverlapSpans(UFieldCategory spanCategory, int8_t firstIndex, UErrorCode& status);
+
+ /**
+ * Sorts the fields: start index first, length second.
+ */
+ void sort();
+
+private:
+ UnicodeString fString;
+ UVector32 fFields;
+};
+
+
+/**
+ * Implementation of FormattedValue based on FormattedStringBuilder.
+ *
+ * The implementation currently revolves around numbers and number fields.
+ * However, it can be generalized in the future when there is a need.
+ *
+ * @author sffc (Shane Carr)
+ */
+// Exported as U_I18N_API for tests
+class U_I18N_API FormattedValueStringBuilderImpl : public UMemory, public FormattedValue {
+public:
+
+ FormattedValueStringBuilderImpl(FormattedStringBuilder::Field numericField);
+
+ virtual ~FormattedValueStringBuilderImpl();
+
+ // Implementation of FormattedValue (const):
+
+ UnicodeString toString(UErrorCode& status) const U_OVERRIDE;
+ UnicodeString toTempString(UErrorCode& status) const U_OVERRIDE;
+ Appendable& appendTo(Appendable& appendable, UErrorCode& status) const U_OVERRIDE;
+ UBool nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const U_OVERRIDE;
+
+ // Additional helper functions:
+ UBool nextFieldPosition(FieldPosition& fp, UErrorCode& status) const;
+ void getAllFieldPositions(FieldPositionIteratorHandler& fpih, UErrorCode& status) const;
+ inline FormattedStringBuilder& getStringRef() {
+ return fString;
+ }
+ inline const FormattedStringBuilder& getStringRef() const {
+ return fString;
+ }
+
+private:
+ FormattedStringBuilder fString;
+ FormattedStringBuilder::Field fNumericField;
+
+ bool nextPositionImpl(ConstrainedFieldPosition& cfpos, FormattedStringBuilder::Field numericField, UErrorCode& status) const;
+ static bool isIntOrGroup(FormattedStringBuilder::Field field);
+ int32_t trimBack(int32_t limit) const;
+ int32_t trimFront(int32_t start) const;
+};
+
+
+// C API Helpers for FormattedValue
+// Magic number as ASCII == "UFV"
+struct UFormattedValueImpl;
+typedef IcuCApiHelper<UFormattedValue, UFormattedValueImpl, 0x55465600> UFormattedValueApiHelper;
+struct UFormattedValueImpl : public UMemory, public UFormattedValueApiHelper {
+ // This pointer should be set by the child class.
+ FormattedValue* fFormattedValue = nullptr;
+};
+
+
+/** Boilerplate to check for valid status before dereferencing the fData pointer. */
+#define UPRV_FORMATTED_VALUE_METHOD_GUARD(returnExpression) \
+ if (U_FAILURE(status)) { \
+ return returnExpression; \
+ } \
+ if (fData == nullptr) { \
+ status = fErrorCode; \
+ return returnExpression; \
+ } \
+
+
+/** Implementation of the methods from U_FORMATTED_VALUE_SUBCLASS_AUTO. */
+#define UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(Name) \
+ Name::Name(Name&& src) U_NOEXCEPT \
+ : fData(src.fData), fErrorCode(src.fErrorCode) { \
+ src.fData = nullptr; \
+ src.fErrorCode = U_INVALID_STATE_ERROR; \
+ } \
+ Name::~Name() { \
+ delete fData; \
+ fData = nullptr; \
+ } \
+ Name& Name::operator=(Name&& src) U_NOEXCEPT { \
+ delete fData; \
+ fData = src.fData; \
+ src.fData = nullptr; \
+ fErrorCode = src.fErrorCode; \
+ src.fErrorCode = U_INVALID_STATE_ERROR; \
+ return *this; \
+ } \
+ UnicodeString Name::toString(UErrorCode& status) const { \
+ UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) \
+ return fData->toString(status); \
+ } \
+ UnicodeString Name::toTempString(UErrorCode& status) const { \
+ UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString()) \
+ return fData->toTempString(status); \
+ } \
+ Appendable& Name::appendTo(Appendable& appendable, UErrorCode& status) const { \
+ UPRV_FORMATTED_VALUE_METHOD_GUARD(appendable) \
+ return fData->appendTo(appendable, status); \
+ } \
+ UBool Name::nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const { \
+ UPRV_FORMATTED_VALUE_METHOD_GUARD(FALSE) \
+ return fData->nextPosition(cfpos, status); \
+ }
+
+
+/** Like UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL but without impl type declarations. */
+#define UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(CType, ImplType, HelperType, Prefix) \
+ U_CAPI CType* U_EXPORT2 \
+ Prefix ## _openResult (UErrorCode* ec) { \
+ if (U_FAILURE(*ec)) { \
+ return nullptr; \
+ } \
+ ImplType* impl = new ImplType(); \
+ if (impl == nullptr) { \
+ *ec = U_MEMORY_ALLOCATION_ERROR; \
+ return nullptr; \
+ } \
+ return static_cast<HelperType*>(impl)->exportForC(); \
+ } \
+ U_DRAFT const UFormattedValue* U_EXPORT2 \
+ Prefix ## _resultAsValue (const CType* uresult, UErrorCode* ec) { \
+ const ImplType* result = HelperType::validate(uresult, *ec); \
+ if (U_FAILURE(*ec)) { return nullptr; } \
+ return static_cast<const UFormattedValueApiHelper*>(result)->exportConstForC(); \
+ } \
+ U_CAPI void U_EXPORT2 \
+ Prefix ## _closeResult (CType* uresult) { \
+ UErrorCode localStatus = U_ZERO_ERROR; \
+ const ImplType* impl = HelperType::validate(uresult, localStatus); \
+ delete impl; \
+ }
+
+
+/**
+ * Implementation of the standard methods for a UFormattedValue "subclass" C API.
+ * @param CPPType The public C++ type, like FormattedList
+ * @param CType The public C type, like UFormattedList
+ * @param ImplType A name to use for the implementation class
+ * @param HelperType A name to use for the "mixin" typedef for C API conversion
+ * @param Prefix The C API prefix, like ulistfmt
+ * @param MagicNumber A unique 32-bit number to use to identify this type
+ */
+#define UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL(CPPType, CType, ImplType, HelperType, Prefix, MagicNumber) \
+ U_NAMESPACE_BEGIN \
+ class ImplType; \
+ typedef IcuCApiHelper<CType, ImplType, MagicNumber> HelperType; \
+ class ImplType : public UFormattedValueImpl, public HelperType { \
+ public: \
+ ImplType(); \
+ ~ImplType(); \
+ CPPType fImpl; \
+ }; \
+ ImplType::ImplType() { \
+ fFormattedValue = &fImpl; \
+ } \
+ ImplType::~ImplType() {} \
+ U_NAMESPACE_END \
+ UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(CType, ImplType, HelperType, Prefix)
+
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+#endif // __FORMVAL_IMPL_H__
diff --git a/contrib/libs/icu/i18n/formattedval_iterimpl.cpp b/contrib/libs/icu/i18n/formattedval_iterimpl.cpp
index 75328fae88..52cdb82a50 100644
--- a/contrib/libs/icu/i18n/formattedval_iterimpl.cpp
+++ b/contrib/libs/icu/i18n/formattedval_iterimpl.cpp
@@ -1,176 +1,176 @@
-// © 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
-
-// This file contains one implementation of FormattedValue.
-// Other independent implementations should go into their own cpp file for
-// better dependency modularization.
-
-#include "formattedval_impl.h"
-#include "putilimp.h"
-
-U_NAMESPACE_BEGIN
-
-
-FormattedValueFieldPositionIteratorImpl::FormattedValueFieldPositionIteratorImpl(
- int32_t initialFieldCapacity,
- UErrorCode& status)
- : fFields(initialFieldCapacity * 4, status) {
-}
-
-FormattedValueFieldPositionIteratorImpl::~FormattedValueFieldPositionIteratorImpl() = default;
-
-UnicodeString FormattedValueFieldPositionIteratorImpl::toString(
- UErrorCode&) const {
- return fString;
-}
-
-UnicodeString FormattedValueFieldPositionIteratorImpl::toTempString(
- UErrorCode&) const {
- // The alias must point to memory owned by this object;
- // fastCopyFrom doesn't do this when using a stack buffer.
- return UnicodeString(TRUE, fString.getBuffer(), fString.length());
-}
-
-Appendable& FormattedValueFieldPositionIteratorImpl::appendTo(
- Appendable& appendable,
- UErrorCode&) const {
- appendable.appendString(fString.getBuffer(), fString.length());
- return appendable;
-}
-
-UBool FormattedValueFieldPositionIteratorImpl::nextPosition(
- ConstrainedFieldPosition& cfpos,
- UErrorCode&) const {
- U_ASSERT(fFields.size() % 4 == 0);
- int32_t numFields = fFields.size() / 4;
- int32_t i = static_cast<int32_t>(cfpos.getInt64IterationContext());
- for (; i < numFields; i++) {
- UFieldCategory category = static_cast<UFieldCategory>(fFields.elementAti(i * 4));
- int32_t field = fFields.elementAti(i * 4 + 1);
- if (cfpos.matchesField(category, field)) {
- int32_t start = fFields.elementAti(i * 4 + 2);
- int32_t limit = fFields.elementAti(i * 4 + 3);
- cfpos.setState(category, field, start, limit);
- break;
- }
- }
- cfpos.setInt64IterationContext(i == numFields ? i : i + 1);
- return i < numFields;
-}
-
-
-FieldPositionIteratorHandler FormattedValueFieldPositionIteratorImpl::getHandler(
- UErrorCode& status) {
- return FieldPositionIteratorHandler(&fFields, status);
-}
-
-void FormattedValueFieldPositionIteratorImpl::appendString(
- UnicodeString string,
- UErrorCode& status) {
- if (U_FAILURE(status)) {
- return;
- }
- fString.append(string);
- // Make the string NUL-terminated
- if (fString.getTerminatedBuffer() == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
-}
-
-
-void FormattedValueFieldPositionIteratorImpl::addOverlapSpans(
- UFieldCategory spanCategory,
- int8_t firstIndex,
- UErrorCode& status) {
- // In order to avoid fancy data structures, this is an O(N^2) algorithm,
- // which should be fine for all real-life applications of this function.
- int32_t s1a = INT32_MAX;
- int32_t s1b = 0;
- int32_t s2a = INT32_MAX;
- int32_t s2b = 0;
- int32_t numFields = fFields.size() / 4;
- for (int32_t i = 0; i<numFields; i++) {
- int32_t field1 = fFields.elementAti(i * 4 + 1);
- for (int32_t j = i + 1; j<numFields; j++) {
- int32_t field2 = fFields.elementAti(j * 4 + 1);
- if (field1 != field2) {
- continue;
- }
- // Found a duplicate
- s1a = uprv_min(s1a, fFields.elementAti(i * 4 + 2));
- s1b = uprv_max(s1b, fFields.elementAti(i * 4 + 3));
- s2a = uprv_min(s2a, fFields.elementAti(j * 4 + 2));
- s2b = uprv_max(s2b, fFields.elementAti(j * 4 + 3));
- break;
- }
- }
- if (s1a != INT32_MAX) {
- // Success: add the two span fields
- fFields.addElement(spanCategory, status);
- fFields.addElement(firstIndex, status);
- fFields.addElement(s1a, status);
- fFields.addElement(s1b, status);
- fFields.addElement(spanCategory, status);
- fFields.addElement(1 - firstIndex, status);
- fFields.addElement(s2a, status);
- fFields.addElement(s2b, status);
- }
-}
-
-
-void FormattedValueFieldPositionIteratorImpl::sort() {
- // Use bubble sort, O(N^2) but easy and no fancy data structures.
- int32_t numFields = fFields.size() / 4;
- while (true) {
- bool isSorted = true;
- for (int32_t i=0; i<numFields-1; i++) {
- int32_t categ1 = fFields.elementAti(i*4 + 0);
- int32_t field1 = fFields.elementAti(i*4 + 1);
- int32_t start1 = fFields.elementAti(i*4 + 2);
- int32_t limit1 = fFields.elementAti(i*4 + 3);
- int32_t categ2 = fFields.elementAti(i*4 + 4);
- int32_t field2 = fFields.elementAti(i*4 + 5);
- int32_t start2 = fFields.elementAti(i*4 + 6);
- int32_t limit2 = fFields.elementAti(i*4 + 7);
- int64_t comparison = 0;
- if (start1 != start2) {
- // Higher start index -> higher rank
- comparison = start2 - start1;
- } else if (limit1 != limit2) {
- // Higher length (end index) -> lower rank
- comparison = limit1 - limit2;
- } else if (categ1 != categ2) {
- // Higher field category -> lower rank
- comparison = categ1 - categ2;
- } else if (field1 != field2) {
- // Higher field -> higher rank
- comparison = field2 - field1;
- }
- if (comparison < 0) {
- // Perform a swap
- isSorted = false;
- fFields.setElementAt(categ2, i*4 + 0);
- fFields.setElementAt(field2, i*4 + 1);
- fFields.setElementAt(start2, i*4 + 2);
- fFields.setElementAt(limit2, i*4 + 3);
- fFields.setElementAt(categ1, i*4 + 4);
- fFields.setElementAt(field1, i*4 + 5);
- fFields.setElementAt(start1, i*4 + 6);
- fFields.setElementAt(limit1, i*4 + 7);
- }
- }
- if (isSorted) {
- break;
- }
- }
-}
-
-
-U_NAMESPACE_END
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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
+
+// This file contains one implementation of FormattedValue.
+// Other independent implementations should go into their own cpp file for
+// better dependency modularization.
+
+#include "formattedval_impl.h"
+#include "putilimp.h"
+
+U_NAMESPACE_BEGIN
+
+
+FormattedValueFieldPositionIteratorImpl::FormattedValueFieldPositionIteratorImpl(
+ int32_t initialFieldCapacity,
+ UErrorCode& status)
+ : fFields(initialFieldCapacity * 4, status) {
+}
+
+FormattedValueFieldPositionIteratorImpl::~FormattedValueFieldPositionIteratorImpl() = default;
+
+UnicodeString FormattedValueFieldPositionIteratorImpl::toString(
+ UErrorCode&) const {
+ return fString;
+}
+
+UnicodeString FormattedValueFieldPositionIteratorImpl::toTempString(
+ UErrorCode&) const {
+ // The alias must point to memory owned by this object;
+ // fastCopyFrom doesn't do this when using a stack buffer.
+ return UnicodeString(TRUE, fString.getBuffer(), fString.length());
+}
+
+Appendable& FormattedValueFieldPositionIteratorImpl::appendTo(
+ Appendable& appendable,
+ UErrorCode&) const {
+ appendable.appendString(fString.getBuffer(), fString.length());
+ return appendable;
+}
+
+UBool FormattedValueFieldPositionIteratorImpl::nextPosition(
+ ConstrainedFieldPosition& cfpos,
+ UErrorCode&) const {
+ U_ASSERT(fFields.size() % 4 == 0);
+ int32_t numFields = fFields.size() / 4;
+ int32_t i = static_cast<int32_t>(cfpos.getInt64IterationContext());
+ for (; i < numFields; i++) {
+ UFieldCategory category = static_cast<UFieldCategory>(fFields.elementAti(i * 4));
+ int32_t field = fFields.elementAti(i * 4 + 1);
+ if (cfpos.matchesField(category, field)) {
+ int32_t start = fFields.elementAti(i * 4 + 2);
+ int32_t limit = fFields.elementAti(i * 4 + 3);
+ cfpos.setState(category, field, start, limit);
+ break;
+ }
+ }
+ cfpos.setInt64IterationContext(i == numFields ? i : i + 1);
+ return i < numFields;
+}
+
+
+FieldPositionIteratorHandler FormattedValueFieldPositionIteratorImpl::getHandler(
+ UErrorCode& status) {
+ return FieldPositionIteratorHandler(&fFields, status);
+}
+
+void FormattedValueFieldPositionIteratorImpl::appendString(
+ UnicodeString string,
+ UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fString.append(string);
+ // Make the string NUL-terminated
+ if (fString.getTerminatedBuffer() == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+}
+
+
+void FormattedValueFieldPositionIteratorImpl::addOverlapSpans(
+ UFieldCategory spanCategory,
+ int8_t firstIndex,
+ UErrorCode& status) {
+ // In order to avoid fancy data structures, this is an O(N^2) algorithm,
+ // which should be fine for all real-life applications of this function.
+ int32_t s1a = INT32_MAX;
+ int32_t s1b = 0;
+ int32_t s2a = INT32_MAX;
+ int32_t s2b = 0;
+ int32_t numFields = fFields.size() / 4;
+ for (int32_t i = 0; i<numFields; i++) {
+ int32_t field1 = fFields.elementAti(i * 4 + 1);
+ for (int32_t j = i + 1; j<numFields; j++) {
+ int32_t field2 = fFields.elementAti(j * 4 + 1);
+ if (field1 != field2) {
+ continue;
+ }
+ // Found a duplicate
+ s1a = uprv_min(s1a, fFields.elementAti(i * 4 + 2));
+ s1b = uprv_max(s1b, fFields.elementAti(i * 4 + 3));
+ s2a = uprv_min(s2a, fFields.elementAti(j * 4 + 2));
+ s2b = uprv_max(s2b, fFields.elementAti(j * 4 + 3));
+ break;
+ }
+ }
+ if (s1a != INT32_MAX) {
+ // Success: add the two span fields
+ fFields.addElement(spanCategory, status);
+ fFields.addElement(firstIndex, status);
+ fFields.addElement(s1a, status);
+ fFields.addElement(s1b, status);
+ fFields.addElement(spanCategory, status);
+ fFields.addElement(1 - firstIndex, status);
+ fFields.addElement(s2a, status);
+ fFields.addElement(s2b, status);
+ }
+}
+
+
+void FormattedValueFieldPositionIteratorImpl::sort() {
+ // Use bubble sort, O(N^2) but easy and no fancy data structures.
+ int32_t numFields = fFields.size() / 4;
+ while (true) {
+ bool isSorted = true;
+ for (int32_t i=0; i<numFields-1; i++) {
+ int32_t categ1 = fFields.elementAti(i*4 + 0);
+ int32_t field1 = fFields.elementAti(i*4 + 1);
+ int32_t start1 = fFields.elementAti(i*4 + 2);
+ int32_t limit1 = fFields.elementAti(i*4 + 3);
+ int32_t categ2 = fFields.elementAti(i*4 + 4);
+ int32_t field2 = fFields.elementAti(i*4 + 5);
+ int32_t start2 = fFields.elementAti(i*4 + 6);
+ int32_t limit2 = fFields.elementAti(i*4 + 7);
+ int64_t comparison = 0;
+ if (start1 != start2) {
+ // Higher start index -> higher rank
+ comparison = start2 - start1;
+ } else if (limit1 != limit2) {
+ // Higher length (end index) -> lower rank
+ comparison = limit1 - limit2;
+ } else if (categ1 != categ2) {
+ // Higher field category -> lower rank
+ comparison = categ1 - categ2;
+ } else if (field1 != field2) {
+ // Higher field -> higher rank
+ comparison = field2 - field1;
+ }
+ if (comparison < 0) {
+ // Perform a swap
+ isSorted = false;
+ fFields.setElementAt(categ2, i*4 + 0);
+ fFields.setElementAt(field2, i*4 + 1);
+ fFields.setElementAt(start2, i*4 + 2);
+ fFields.setElementAt(limit2, i*4 + 3);
+ fFields.setElementAt(categ1, i*4 + 4);
+ fFields.setElementAt(field1, i*4 + 5);
+ fFields.setElementAt(start1, i*4 + 6);
+ fFields.setElementAt(limit1, i*4 + 7);
+ }
+ }
+ if (isSorted) {
+ break;
+ }
+ }
+}
+
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/formattedval_sbimpl.cpp b/contrib/libs/icu/i18n/formattedval_sbimpl.cpp
index dfe3af6686..79e9ede975 100644
--- a/contrib/libs/icu/i18n/formattedval_sbimpl.cpp
+++ b/contrib/libs/icu/i18n/formattedval_sbimpl.cpp
@@ -1,207 +1,207 @@
-// © 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
-
-// This file contains one implementation of FormattedValue.
-// Other independent implementations should go into their own cpp file for
-// better dependency modularization.
-
-#include "unicode/ustring.h"
-#include "formattedval_impl.h"
-#include "number_types.h"
-#include "formatted_string_builder.h"
-#include "number_utils.h"
-#include "static_unicode_sets.h"
-
-U_NAMESPACE_BEGIN
-
-
-typedef FormattedStringBuilder::Field Field;
-
-
-FormattedValueStringBuilderImpl::FormattedValueStringBuilderImpl(Field numericField)
- : fNumericField(numericField) {
-}
-
-FormattedValueStringBuilderImpl::~FormattedValueStringBuilderImpl() {
-}
-
-
-UnicodeString FormattedValueStringBuilderImpl::toString(UErrorCode&) const {
- return fString.toUnicodeString();
-}
-
-UnicodeString FormattedValueStringBuilderImpl::toTempString(UErrorCode&) const {
- return fString.toTempUnicodeString();
-}
-
-Appendable& FormattedValueStringBuilderImpl::appendTo(Appendable& appendable, UErrorCode&) const {
- appendable.appendString(fString.chars(), fString.length());
- return appendable;
-}
-
-UBool FormattedValueStringBuilderImpl::nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const {
- // NOTE: MSVC sometimes complains when implicitly converting between bool and UBool
- return nextPositionImpl(cfpos, fNumericField, status) ? TRUE : FALSE;
-}
-
-UBool FormattedValueStringBuilderImpl::nextFieldPosition(FieldPosition& fp, UErrorCode& status) const {
- int32_t rawField = fp.getField();
-
- if (rawField == FieldPosition::DONT_CARE) {
- return FALSE;
- }
-
- if (rawField < 0 || rawField >= UNUM_FIELD_COUNT) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return FALSE;
- }
-
- ConstrainedFieldPosition cfpos;
- cfpos.constrainField(UFIELD_CATEGORY_NUMBER, rawField);
- cfpos.setState(UFIELD_CATEGORY_NUMBER, rawField, fp.getBeginIndex(), fp.getEndIndex());
- if (nextPositionImpl(cfpos, kUndefinedField, status)) {
- fp.setBeginIndex(cfpos.getStart());
- fp.setEndIndex(cfpos.getLimit());
- return TRUE;
- }
-
- // Special case: fraction should start after integer if fraction is not present
- if (rawField == UNUM_FRACTION_FIELD && fp.getEndIndex() == 0) {
- bool inside = false;
- int32_t i = fString.fZero;
- for (; i < fString.fZero + fString.fLength; i++) {
- if (isIntOrGroup(fString.getFieldPtr()[i]) || fString.getFieldPtr()[i] == Field(UFIELD_CATEGORY_NUMBER, UNUM_DECIMAL_SEPARATOR_FIELD)) {
- inside = true;
- } else if (inside) {
- break;
- }
- }
- fp.setBeginIndex(i - fString.fZero);
- fp.setEndIndex(i - fString.fZero);
- }
-
- return FALSE;
-}
-
-void FormattedValueStringBuilderImpl::getAllFieldPositions(FieldPositionIteratorHandler& fpih,
- UErrorCode& status) const {
- ConstrainedFieldPosition cfpos;
- while (nextPositionImpl(cfpos, kUndefinedField, status)) {
- fpih.addAttribute(cfpos.getField(), cfpos.getStart(), cfpos.getLimit());
- }
-}
-
-// Signal the end of the string using a field that doesn't exist and that is
-// different from kUndefinedField, which is used for "null field".
-static constexpr Field kEndField = Field(0xf, 0xf);
-
-bool FormattedValueStringBuilderImpl::nextPositionImpl(ConstrainedFieldPosition& cfpos, Field numericField, UErrorCode& /*status*/) const {
- int32_t fieldStart = -1;
- Field currField = kUndefinedField;
- for (int32_t i = fString.fZero + cfpos.getLimit(); i <= fString.fZero + fString.fLength; i++) {
- Field _field = (i < fString.fZero + fString.fLength) ? fString.getFieldPtr()[i] : kEndField;
- // Case 1: currently scanning a field.
- if (currField != kUndefinedField) {
- if (currField != _field) {
- int32_t end = i - fString.fZero;
- // Grouping separators can be whitespace; don't throw them out!
- if (currField != Field(UFIELD_CATEGORY_NUMBER, UNUM_GROUPING_SEPARATOR_FIELD)) {
- end = trimBack(i - fString.fZero);
- }
- if (end <= fieldStart) {
- // Entire field position is ignorable; skip.
- fieldStart = -1;
- currField = kUndefinedField;
- i--; // look at this index again
- continue;
- }
- int32_t start = fieldStart;
- if (currField != Field(UFIELD_CATEGORY_NUMBER, UNUM_GROUPING_SEPARATOR_FIELD)) {
- start = trimFront(start);
- }
- cfpos.setState(currField.getCategory(), currField.getField(), start, end);
- return true;
- }
- continue;
- }
- // Special case: coalesce the INTEGER if we are pointing at the end of the INTEGER.
- if (cfpos.matchesField(UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD)
- && i > fString.fZero
- // don't return the same field twice in a row:
- && i - fString.fZero > cfpos.getLimit()
- && isIntOrGroup(fString.getFieldPtr()[i - 1])
- && !isIntOrGroup(_field)) {
- int j = i - 1;
- for (; j >= fString.fZero && isIntOrGroup(fString.getFieldPtr()[j]); j--) {}
- cfpos.setState(
- UFIELD_CATEGORY_NUMBER,
- UNUM_INTEGER_FIELD,
- j - fString.fZero + 1,
- i - fString.fZero);
- return true;
- }
- // Special case: coalesce NUMERIC if we are pointing at the end of the NUMERIC.
- if (numericField != kUndefinedField
- && cfpos.matchesField(numericField.getCategory(), numericField.getField())
- && i > fString.fZero
- // don't return the same field twice in a row:
- && (i - fString.fZero > cfpos.getLimit()
- || cfpos.getCategory() != numericField.getCategory()
- || cfpos.getField() != numericField.getField())
- && fString.getFieldPtr()[i - 1].isNumeric()
- && !_field.isNumeric()) {
- int j = i - 1;
- for (; j >= fString.fZero && fString.getFieldPtr()[j].isNumeric(); j--) {}
- cfpos.setState(
- numericField.getCategory(),
- numericField.getField(),
- j - fString.fZero + 1,
- i - fString.fZero);
- return true;
- }
- // Special case: skip over INTEGER; will be coalesced later.
- if (_field == Field(UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD)) {
- _field = kUndefinedField;
- }
- // Case 2: no field starting at this position.
- if (_field.isUndefined() || _field == kEndField) {
- continue;
- }
- // Case 3: check for field starting at this position
- if (cfpos.matchesField(_field.getCategory(), _field.getField())) {
- fieldStart = i - fString.fZero;
- currField = _field;
- }
- }
-
- U_ASSERT(currField == kUndefinedField);
- return false;
-}
-
-bool FormattedValueStringBuilderImpl::isIntOrGroup(Field field) {
- return field == Field(UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD)
- || field == Field(UFIELD_CATEGORY_NUMBER, UNUM_GROUPING_SEPARATOR_FIELD);
-}
-
-int32_t FormattedValueStringBuilderImpl::trimBack(int32_t limit) const {
- return unisets::get(unisets::DEFAULT_IGNORABLES)->spanBack(
- fString.getCharPtr() + fString.fZero,
- limit,
- USET_SPAN_CONTAINED);
-}
-
-int32_t FormattedValueStringBuilderImpl::trimFront(int32_t start) const {
- return start + unisets::get(unisets::DEFAULT_IGNORABLES)->span(
- fString.getCharPtr() + fString.fZero + start,
- fString.fLength - start,
- USET_SPAN_CONTAINED);
-}
-
-
-U_NAMESPACE_END
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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
+
+// This file contains one implementation of FormattedValue.
+// Other independent implementations should go into their own cpp file for
+// better dependency modularization.
+
+#include "unicode/ustring.h"
+#include "formattedval_impl.h"
+#include "number_types.h"
+#include "formatted_string_builder.h"
+#include "number_utils.h"
+#include "static_unicode_sets.h"
+
+U_NAMESPACE_BEGIN
+
+
+typedef FormattedStringBuilder::Field Field;
+
+
+FormattedValueStringBuilderImpl::FormattedValueStringBuilderImpl(Field numericField)
+ : fNumericField(numericField) {
+}
+
+FormattedValueStringBuilderImpl::~FormattedValueStringBuilderImpl() {
+}
+
+
+UnicodeString FormattedValueStringBuilderImpl::toString(UErrorCode&) const {
+ return fString.toUnicodeString();
+}
+
+UnicodeString FormattedValueStringBuilderImpl::toTempString(UErrorCode&) const {
+ return fString.toTempUnicodeString();
+}
+
+Appendable& FormattedValueStringBuilderImpl::appendTo(Appendable& appendable, UErrorCode&) const {
+ appendable.appendString(fString.chars(), fString.length());
+ return appendable;
+}
+
+UBool FormattedValueStringBuilderImpl::nextPosition(ConstrainedFieldPosition& cfpos, UErrorCode& status) const {
+ // NOTE: MSVC sometimes complains when implicitly converting between bool and UBool
+ return nextPositionImpl(cfpos, fNumericField, status) ? TRUE : FALSE;
+}
+
+UBool FormattedValueStringBuilderImpl::nextFieldPosition(FieldPosition& fp, UErrorCode& status) const {
+ int32_t rawField = fp.getField();
+
+ if (rawField == FieldPosition::DONT_CARE) {
+ return FALSE;
+ }
+
+ if (rawField < 0 || rawField >= UNUM_FIELD_COUNT) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return FALSE;
+ }
+
+ ConstrainedFieldPosition cfpos;
+ cfpos.constrainField(UFIELD_CATEGORY_NUMBER, rawField);
+ cfpos.setState(UFIELD_CATEGORY_NUMBER, rawField, fp.getBeginIndex(), fp.getEndIndex());
+ if (nextPositionImpl(cfpos, kUndefinedField, status)) {
+ fp.setBeginIndex(cfpos.getStart());
+ fp.setEndIndex(cfpos.getLimit());
+ return TRUE;
+ }
+
+ // Special case: fraction should start after integer if fraction is not present
+ if (rawField == UNUM_FRACTION_FIELD && fp.getEndIndex() == 0) {
+ bool inside = false;
+ int32_t i = fString.fZero;
+ for (; i < fString.fZero + fString.fLength; i++) {
+ if (isIntOrGroup(fString.getFieldPtr()[i]) || fString.getFieldPtr()[i] == Field(UFIELD_CATEGORY_NUMBER, UNUM_DECIMAL_SEPARATOR_FIELD)) {
+ inside = true;
+ } else if (inside) {
+ break;
+ }
+ }
+ fp.setBeginIndex(i - fString.fZero);
+ fp.setEndIndex(i - fString.fZero);
+ }
+
+ return FALSE;
+}
+
+void FormattedValueStringBuilderImpl::getAllFieldPositions(FieldPositionIteratorHandler& fpih,
+ UErrorCode& status) const {
+ ConstrainedFieldPosition cfpos;
+ while (nextPositionImpl(cfpos, kUndefinedField, status)) {
+ fpih.addAttribute(cfpos.getField(), cfpos.getStart(), cfpos.getLimit());
+ }
+}
+
+// Signal the end of the string using a field that doesn't exist and that is
+// different from kUndefinedField, which is used for "null field".
+static constexpr Field kEndField = Field(0xf, 0xf);
+
+bool FormattedValueStringBuilderImpl::nextPositionImpl(ConstrainedFieldPosition& cfpos, Field numericField, UErrorCode& /*status*/) const {
+ int32_t fieldStart = -1;
+ Field currField = kUndefinedField;
+ for (int32_t i = fString.fZero + cfpos.getLimit(); i <= fString.fZero + fString.fLength; i++) {
+ Field _field = (i < fString.fZero + fString.fLength) ? fString.getFieldPtr()[i] : kEndField;
+ // Case 1: currently scanning a field.
+ if (currField != kUndefinedField) {
+ if (currField != _field) {
+ int32_t end = i - fString.fZero;
+ // Grouping separators can be whitespace; don't throw them out!
+ if (currField != Field(UFIELD_CATEGORY_NUMBER, UNUM_GROUPING_SEPARATOR_FIELD)) {
+ end = trimBack(i - fString.fZero);
+ }
+ if (end <= fieldStart) {
+ // Entire field position is ignorable; skip.
+ fieldStart = -1;
+ currField = kUndefinedField;
+ i--; // look at this index again
+ continue;
+ }
+ int32_t start = fieldStart;
+ if (currField != Field(UFIELD_CATEGORY_NUMBER, UNUM_GROUPING_SEPARATOR_FIELD)) {
+ start = trimFront(start);
+ }
+ cfpos.setState(currField.getCategory(), currField.getField(), start, end);
+ return true;
+ }
+ continue;
+ }
+ // Special case: coalesce the INTEGER if we are pointing at the end of the INTEGER.
+ if (cfpos.matchesField(UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD)
+ && i > fString.fZero
+ // don't return the same field twice in a row:
+ && i - fString.fZero > cfpos.getLimit()
+ && isIntOrGroup(fString.getFieldPtr()[i - 1])
+ && !isIntOrGroup(_field)) {
+ int j = i - 1;
+ for (; j >= fString.fZero && isIntOrGroup(fString.getFieldPtr()[j]); j--) {}
+ cfpos.setState(
+ UFIELD_CATEGORY_NUMBER,
+ UNUM_INTEGER_FIELD,
+ j - fString.fZero + 1,
+ i - fString.fZero);
+ return true;
+ }
+ // Special case: coalesce NUMERIC if we are pointing at the end of the NUMERIC.
+ if (numericField != kUndefinedField
+ && cfpos.matchesField(numericField.getCategory(), numericField.getField())
+ && i > fString.fZero
+ // don't return the same field twice in a row:
+ && (i - fString.fZero > cfpos.getLimit()
+ || cfpos.getCategory() != numericField.getCategory()
+ || cfpos.getField() != numericField.getField())
+ && fString.getFieldPtr()[i - 1].isNumeric()
+ && !_field.isNumeric()) {
+ int j = i - 1;
+ for (; j >= fString.fZero && fString.getFieldPtr()[j].isNumeric(); j--) {}
+ cfpos.setState(
+ numericField.getCategory(),
+ numericField.getField(),
+ j - fString.fZero + 1,
+ i - fString.fZero);
+ return true;
+ }
+ // Special case: skip over INTEGER; will be coalesced later.
+ if (_field == Field(UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD)) {
+ _field = kUndefinedField;
+ }
+ // Case 2: no field starting at this position.
+ if (_field.isUndefined() || _field == kEndField) {
+ continue;
+ }
+ // Case 3: check for field starting at this position
+ if (cfpos.matchesField(_field.getCategory(), _field.getField())) {
+ fieldStart = i - fString.fZero;
+ currField = _field;
+ }
+ }
+
+ U_ASSERT(currField == kUndefinedField);
+ return false;
+}
+
+bool FormattedValueStringBuilderImpl::isIntOrGroup(Field field) {
+ return field == Field(UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD)
+ || field == Field(UFIELD_CATEGORY_NUMBER, UNUM_GROUPING_SEPARATOR_FIELD);
+}
+
+int32_t FormattedValueStringBuilderImpl::trimBack(int32_t limit) const {
+ return unisets::get(unisets::DEFAULT_IGNORABLES)->spanBack(
+ fString.getCharPtr() + fString.fZero,
+ limit,
+ USET_SPAN_CONTAINED);
+}
+
+int32_t FormattedValueStringBuilderImpl::trimFront(int32_t start) const {
+ return start + unisets::get(unisets::DEFAULT_IGNORABLES)->span(
+ fString.getCharPtr() + fString.fZero + start,
+ fString.fLength - start,
+ USET_SPAN_CONTAINED);
+}
+
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/formattedvalue.cpp b/contrib/libs/icu/i18n/formattedvalue.cpp
index e2c9c42fc8..aada0f903f 100644
--- a/contrib/libs/icu/i18n/formattedvalue.cpp
+++ b/contrib/libs/icu/i18n/formattedvalue.cpp
@@ -1,232 +1,232 @@
-// © 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
-
-#include "unicode/formattedvalue.h"
-#include "formattedval_impl.h"
-#include "capi_helper.h"
-
-U_NAMESPACE_BEGIN
-
-
-ConstrainedFieldPosition::ConstrainedFieldPosition() {}
-
-ConstrainedFieldPosition::~ConstrainedFieldPosition() {}
-
-void ConstrainedFieldPosition::reset() {
- fContext = 0LL;
- fField = 0;
- fStart = 0;
- fLimit = 0;
- fConstraint = UCFPOS_CONSTRAINT_NONE;
- fCategory = UFIELD_CATEGORY_UNDEFINED;
-}
-
-void ConstrainedFieldPosition::constrainCategory(int32_t category) {
- fConstraint = UCFPOS_CONSTRAINT_CATEGORY;
- fCategory = category;
-}
-
-void ConstrainedFieldPosition::constrainField(int32_t category, int32_t field) {
- fConstraint = UCFPOS_CONSTRAINT_FIELD;
- fCategory = category;
- fField = field;
-}
-
-void ConstrainedFieldPosition::setInt64IterationContext(int64_t context) {
- fContext = context;
-}
-
-UBool ConstrainedFieldPosition::matchesField(int32_t category, int32_t field) const {
- switch (fConstraint) {
- case UCFPOS_CONSTRAINT_NONE:
- return TRUE;
- case UCFPOS_CONSTRAINT_CATEGORY:
- return fCategory == category;
- case UCFPOS_CONSTRAINT_FIELD:
- return fCategory == category && fField == field;
- default:
- UPRV_UNREACHABLE;
- }
-}
-
-void ConstrainedFieldPosition::setState(
- int32_t category,
- int32_t field,
- int32_t start,
- int32_t limit) {
- fCategory = category;
- fField = field;
- fStart = start;
- fLimit = limit;
-}
-
-
-FormattedValue::~FormattedValue() = default;
-
-
-///////////////////////
-/// C API FUNCTIONS ///
-///////////////////////
-
-struct UConstrainedFieldPositionImpl : public UMemory,
- // Magic number as ASCII == "UCF"
- public IcuCApiHelper<UConstrainedFieldPosition, UConstrainedFieldPositionImpl, 0x55434600> {
- ConstrainedFieldPosition fImpl;
-};
-
-U_CAPI UConstrainedFieldPosition* U_EXPORT2
-ucfpos_open(UErrorCode* ec) {
- auto* impl = new UConstrainedFieldPositionImpl();
- if (impl == nullptr) {
- *ec = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
- return impl->exportForC();
-}
-
-U_CAPI void U_EXPORT2
-ucfpos_reset(UConstrainedFieldPosition* ptr, UErrorCode* ec) {
- auto* impl = UConstrainedFieldPositionImpl::validate(ptr, *ec);
- if (U_FAILURE(*ec)) {
- return;
- }
- impl->fImpl.reset();
-}
-
-U_CAPI void U_EXPORT2
-ucfpos_constrainCategory(UConstrainedFieldPosition* ptr, int32_t category, UErrorCode* ec) {
- auto* impl = UConstrainedFieldPositionImpl::validate(ptr, *ec);
- if (U_FAILURE(*ec)) {
- return;
- }
- impl->fImpl.constrainCategory(category);
-}
-
-U_CAPI void U_EXPORT2
-ucfpos_constrainField(UConstrainedFieldPosition* ptr, int32_t category, int32_t field, UErrorCode* ec) {
- auto* impl = UConstrainedFieldPositionImpl::validate(ptr, *ec);
- if (U_FAILURE(*ec)) {
- return;
- }
- impl->fImpl.constrainField(category, field);
-}
-
-U_CAPI int32_t U_EXPORT2
-ucfpos_getCategory(const UConstrainedFieldPosition* ptr, UErrorCode* ec) {
- const auto* impl = UConstrainedFieldPositionImpl::validate(ptr, *ec);
- if (U_FAILURE(*ec)) {
- return UFIELD_CATEGORY_UNDEFINED;
- }
- return impl->fImpl.getCategory();
-}
-
-U_CAPI int32_t U_EXPORT2
-ucfpos_getField(const UConstrainedFieldPosition* ptr, UErrorCode* ec) {
- const auto* impl = UConstrainedFieldPositionImpl::validate(ptr, *ec);
- if (U_FAILURE(*ec)) {
- return 0;
- }
- return impl->fImpl.getField();
-}
-
-U_CAPI void U_EXPORT2
-ucfpos_getIndexes(const UConstrainedFieldPosition* ptr, int32_t* pStart, int32_t* pLimit, UErrorCode* ec) {
- const auto* impl = UConstrainedFieldPositionImpl::validate(ptr, *ec);
- if (U_FAILURE(*ec)) {
- return;
- }
- *pStart = impl->fImpl.getStart();
- *pLimit = impl->fImpl.getLimit();
-}
-
-U_CAPI int64_t U_EXPORT2
-ucfpos_getInt64IterationContext(const UConstrainedFieldPosition* ptr, UErrorCode* ec) {
- const auto* impl = UConstrainedFieldPositionImpl::validate(ptr, *ec);
- if (U_FAILURE(*ec)) {
- return 0;
- }
- return impl->fImpl.getInt64IterationContext();
-}
-
-U_CAPI void U_EXPORT2
-ucfpos_setInt64IterationContext(UConstrainedFieldPosition* ptr, int64_t context, UErrorCode* ec) {
- auto* impl = UConstrainedFieldPositionImpl::validate(ptr, *ec);
- if (U_FAILURE(*ec)) {
- return;
- }
- impl->fImpl.setInt64IterationContext(context);
-}
-
-U_CAPI UBool U_EXPORT2
-ucfpos_matchesField(const UConstrainedFieldPosition* ptr, int32_t category, int32_t field, UErrorCode* ec) {
- const auto* impl = UConstrainedFieldPositionImpl::validate(ptr, *ec);
- if (U_FAILURE(*ec)) {
- return 0;
- }
- return impl->fImpl.matchesField(category, field);
-}
-
-U_CAPI void U_EXPORT2
-ucfpos_setState(
- UConstrainedFieldPosition* ptr,
- int32_t category,
- int32_t field,
- int32_t start,
- int32_t limit,
- UErrorCode* ec) {
- auto* impl = UConstrainedFieldPositionImpl::validate(ptr, *ec);
- if (U_FAILURE(*ec)) {
- return;
- }
- impl->fImpl.setState(category, field, start, limit);
-}
-
-U_CAPI void U_EXPORT2
-ucfpos_close(UConstrainedFieldPosition* ptr) {
- UErrorCode localStatus = U_ZERO_ERROR;
- auto* impl = UConstrainedFieldPositionImpl::validate(ptr, localStatus);
- delete impl;
-}
-
-
-U_DRAFT const UChar* U_EXPORT2
-ufmtval_getString(
- const UFormattedValue* ufmtval,
- int32_t* pLength,
- UErrorCode* ec) {
- const auto* impl = UFormattedValueApiHelper::validate(ufmtval, *ec);
- if (U_FAILURE(*ec)) {
- return nullptr;
- }
- UnicodeString readOnlyAlias = impl->fFormattedValue->toTempString(*ec);
- if (U_FAILURE(*ec)) {
- return nullptr;
- }
- if (pLength != nullptr) {
- *pLength = readOnlyAlias.length();
- }
- return readOnlyAlias.getBuffer();
-}
-
-
-U_DRAFT UBool U_EXPORT2
-ufmtval_nextPosition(
- const UFormattedValue* ufmtval,
- UConstrainedFieldPosition* ucfpos,
- UErrorCode* ec) {
- const auto* fmtval = UFormattedValueApiHelper::validate(ufmtval, *ec);
- auto* cfpos = UConstrainedFieldPositionImpl::validate(ucfpos, *ec);
- if (U_FAILURE(*ec)) {
- return FALSE;
- }
- return fmtval->fFormattedValue->nextPosition(cfpos->fImpl, *ec);
-}
-
-
-U_NAMESPACE_END
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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
+
+#include "unicode/formattedvalue.h"
+#include "formattedval_impl.h"
+#include "capi_helper.h"
+
+U_NAMESPACE_BEGIN
+
+
+ConstrainedFieldPosition::ConstrainedFieldPosition() {}
+
+ConstrainedFieldPosition::~ConstrainedFieldPosition() {}
+
+void ConstrainedFieldPosition::reset() {
+ fContext = 0LL;
+ fField = 0;
+ fStart = 0;
+ fLimit = 0;
+ fConstraint = UCFPOS_CONSTRAINT_NONE;
+ fCategory = UFIELD_CATEGORY_UNDEFINED;
+}
+
+void ConstrainedFieldPosition::constrainCategory(int32_t category) {
+ fConstraint = UCFPOS_CONSTRAINT_CATEGORY;
+ fCategory = category;
+}
+
+void ConstrainedFieldPosition::constrainField(int32_t category, int32_t field) {
+ fConstraint = UCFPOS_CONSTRAINT_FIELD;
+ fCategory = category;
+ fField = field;
+}
+
+void ConstrainedFieldPosition::setInt64IterationContext(int64_t context) {
+ fContext = context;
+}
+
+UBool ConstrainedFieldPosition::matchesField(int32_t category, int32_t field) const {
+ switch (fConstraint) {
+ case UCFPOS_CONSTRAINT_NONE:
+ return TRUE;
+ case UCFPOS_CONSTRAINT_CATEGORY:
+ return fCategory == category;
+ case UCFPOS_CONSTRAINT_FIELD:
+ return fCategory == category && fField == field;
+ default:
+ UPRV_UNREACHABLE;
+ }
+}
+
+void ConstrainedFieldPosition::setState(
+ int32_t category,
+ int32_t field,
+ int32_t start,
+ int32_t limit) {
+ fCategory = category;
+ fField = field;
+ fStart = start;
+ fLimit = limit;
+}
+
+
+FormattedValue::~FormattedValue() = default;
+
+
+///////////////////////
+/// C API FUNCTIONS ///
+///////////////////////
+
+struct UConstrainedFieldPositionImpl : public UMemory,
+ // Magic number as ASCII == "UCF"
+ public IcuCApiHelper<UConstrainedFieldPosition, UConstrainedFieldPositionImpl, 0x55434600> {
+ ConstrainedFieldPosition fImpl;
+};
+
+U_CAPI UConstrainedFieldPosition* U_EXPORT2
+ucfpos_open(UErrorCode* ec) {
+ auto* impl = new UConstrainedFieldPositionImpl();
+ if (impl == nullptr) {
+ *ec = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+ return impl->exportForC();
+}
+
+U_CAPI void U_EXPORT2
+ucfpos_reset(UConstrainedFieldPosition* ptr, UErrorCode* ec) {
+ auto* impl = UConstrainedFieldPositionImpl::validate(ptr, *ec);
+ if (U_FAILURE(*ec)) {
+ return;
+ }
+ impl->fImpl.reset();
+}
+
+U_CAPI void U_EXPORT2
+ucfpos_constrainCategory(UConstrainedFieldPosition* ptr, int32_t category, UErrorCode* ec) {
+ auto* impl = UConstrainedFieldPositionImpl::validate(ptr, *ec);
+ if (U_FAILURE(*ec)) {
+ return;
+ }
+ impl->fImpl.constrainCategory(category);
+}
+
+U_CAPI void U_EXPORT2
+ucfpos_constrainField(UConstrainedFieldPosition* ptr, int32_t category, int32_t field, UErrorCode* ec) {
+ auto* impl = UConstrainedFieldPositionImpl::validate(ptr, *ec);
+ if (U_FAILURE(*ec)) {
+ return;
+ }
+ impl->fImpl.constrainField(category, field);
+}
+
+U_CAPI int32_t U_EXPORT2
+ucfpos_getCategory(const UConstrainedFieldPosition* ptr, UErrorCode* ec) {
+ const auto* impl = UConstrainedFieldPositionImpl::validate(ptr, *ec);
+ if (U_FAILURE(*ec)) {
+ return UFIELD_CATEGORY_UNDEFINED;
+ }
+ return impl->fImpl.getCategory();
+}
+
+U_CAPI int32_t U_EXPORT2
+ucfpos_getField(const UConstrainedFieldPosition* ptr, UErrorCode* ec) {
+ const auto* impl = UConstrainedFieldPositionImpl::validate(ptr, *ec);
+ if (U_FAILURE(*ec)) {
+ return 0;
+ }
+ return impl->fImpl.getField();
+}
+
+U_CAPI void U_EXPORT2
+ucfpos_getIndexes(const UConstrainedFieldPosition* ptr, int32_t* pStart, int32_t* pLimit, UErrorCode* ec) {
+ const auto* impl = UConstrainedFieldPositionImpl::validate(ptr, *ec);
+ if (U_FAILURE(*ec)) {
+ return;
+ }
+ *pStart = impl->fImpl.getStart();
+ *pLimit = impl->fImpl.getLimit();
+}
+
+U_CAPI int64_t U_EXPORT2
+ucfpos_getInt64IterationContext(const UConstrainedFieldPosition* ptr, UErrorCode* ec) {
+ const auto* impl = UConstrainedFieldPositionImpl::validate(ptr, *ec);
+ if (U_FAILURE(*ec)) {
+ return 0;
+ }
+ return impl->fImpl.getInt64IterationContext();
+}
+
+U_CAPI void U_EXPORT2
+ucfpos_setInt64IterationContext(UConstrainedFieldPosition* ptr, int64_t context, UErrorCode* ec) {
+ auto* impl = UConstrainedFieldPositionImpl::validate(ptr, *ec);
+ if (U_FAILURE(*ec)) {
+ return;
+ }
+ impl->fImpl.setInt64IterationContext(context);
+}
+
+U_CAPI UBool U_EXPORT2
+ucfpos_matchesField(const UConstrainedFieldPosition* ptr, int32_t category, int32_t field, UErrorCode* ec) {
+ const auto* impl = UConstrainedFieldPositionImpl::validate(ptr, *ec);
+ if (U_FAILURE(*ec)) {
+ return 0;
+ }
+ return impl->fImpl.matchesField(category, field);
+}
+
+U_CAPI void U_EXPORT2
+ucfpos_setState(
+ UConstrainedFieldPosition* ptr,
+ int32_t category,
+ int32_t field,
+ int32_t start,
+ int32_t limit,
+ UErrorCode* ec) {
+ auto* impl = UConstrainedFieldPositionImpl::validate(ptr, *ec);
+ if (U_FAILURE(*ec)) {
+ return;
+ }
+ impl->fImpl.setState(category, field, start, limit);
+}
+
+U_CAPI void U_EXPORT2
+ucfpos_close(UConstrainedFieldPosition* ptr) {
+ UErrorCode localStatus = U_ZERO_ERROR;
+ auto* impl = UConstrainedFieldPositionImpl::validate(ptr, localStatus);
+ delete impl;
+}
+
+
+U_DRAFT const UChar* U_EXPORT2
+ufmtval_getString(
+ const UFormattedValue* ufmtval,
+ int32_t* pLength,
+ UErrorCode* ec) {
+ const auto* impl = UFormattedValueApiHelper::validate(ufmtval, *ec);
+ if (U_FAILURE(*ec)) {
+ return nullptr;
+ }
+ UnicodeString readOnlyAlias = impl->fFormattedValue->toTempString(*ec);
+ if (U_FAILURE(*ec)) {
+ return nullptr;
+ }
+ if (pLength != nullptr) {
+ *pLength = readOnlyAlias.length();
+ }
+ return readOnlyAlias.getBuffer();
+}
+
+
+U_DRAFT UBool U_EXPORT2
+ufmtval_nextPosition(
+ const UFormattedValue* ufmtval,
+ UConstrainedFieldPosition* ucfpos,
+ UErrorCode* ec) {
+ const auto* fmtval = UFormattedValueApiHelper::validate(ufmtval, *ec);
+ auto* cfpos = UConstrainedFieldPositionImpl::validate(ucfpos, *ec);
+ if (U_FAILURE(*ec)) {
+ return FALSE;
+ }
+ return fmtval->fFormattedValue->nextPosition(cfpos->fImpl, *ec);
+}
+
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/fphdlimp.cpp b/contrib/libs/icu/i18n/fphdlimp.cpp
index f51bf4bae7..a15711f3ae 100644
--- a/contrib/libs/icu/i18n/fphdlimp.cpp
+++ b/contrib/libs/icu/i18n/fphdlimp.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -22,8 +22,8 @@ U_NAMESPACE_BEGIN
FieldPositionHandler::~FieldPositionHandler() {
}
-void FieldPositionHandler::setShift(int32_t delta) {
- fShift = delta;
+void FieldPositionHandler::setShift(int32_t delta) {
+ fShift = delta;
}
@@ -38,10 +38,10 @@ FieldPositionOnlyHandler::~FieldPositionOnlyHandler() {
void
FieldPositionOnlyHandler::addAttribute(int32_t id, int32_t start, int32_t limit) {
- if (pos.getField() == id && (!acceptFirstOnly || !seenFirst)) {
- seenFirst = TRUE;
- pos.setBeginIndex(start + fShift);
- pos.setEndIndex(limit + fShift);
+ if (pos.getField() == id && (!acceptFirstOnly || !seenFirst)) {
+ seenFirst = TRUE;
+ pos.setBeginIndex(start + fShift);
+ pos.setEndIndex(limit + fShift);
}
}
@@ -58,27 +58,27 @@ FieldPositionOnlyHandler::isRecording(void) const {
return pos.getField() != FieldPosition::DONT_CARE;
}
-void FieldPositionOnlyHandler::setAcceptFirstOnly(UBool acceptFirstOnly) {
- this->acceptFirstOnly = acceptFirstOnly;
-}
-
+void FieldPositionOnlyHandler::setAcceptFirstOnly(UBool acceptFirstOnly) {
+ this->acceptFirstOnly = acceptFirstOnly;
+}
+
// utility subclass FieldPositionIteratorHandler
FieldPositionIteratorHandler::FieldPositionIteratorHandler(FieldPositionIterator* posIter,
UErrorCode& _status)
- : iter(posIter), vec(NULL), status(_status), fCategory(UFIELD_CATEGORY_UNDEFINED) {
+ : iter(posIter), vec(NULL), status(_status), fCategory(UFIELD_CATEGORY_UNDEFINED) {
if (iter && U_SUCCESS(status)) {
vec = new UVector32(status);
}
}
-FieldPositionIteratorHandler::FieldPositionIteratorHandler(
- UVector32* vec,
- UErrorCode& status)
- : iter(nullptr), vec(vec), status(status), fCategory(UFIELD_CATEGORY_UNDEFINED) {
-}
-
+FieldPositionIteratorHandler::FieldPositionIteratorHandler(
+ UVector32* vec,
+ UErrorCode& status)
+ : iter(nullptr), vec(vec), status(status), fCategory(UFIELD_CATEGORY_UNDEFINED) {
+}
+
FieldPositionIteratorHandler::~FieldPositionIteratorHandler() {
// setData adopts the vec regardless of status, so it's safe to null it
if (iter) {
@@ -90,12 +90,12 @@ FieldPositionIteratorHandler::~FieldPositionIteratorHandler() {
void
FieldPositionIteratorHandler::addAttribute(int32_t id, int32_t start, int32_t limit) {
- if (vec && U_SUCCESS(status) && start < limit) {
+ if (vec && U_SUCCESS(status) && start < limit) {
int32_t size = vec->size();
- vec->addElement(fCategory, status);
+ vec->addElement(fCategory, status);
vec->addElement(id, status);
- vec->addElement(start + fShift, status);
- vec->addElement(limit + fShift, status);
+ vec->addElement(start + fShift, status);
+ vec->addElement(limit + fShift, status);
if (!U_SUCCESS(status)) {
vec->setSize(size);
}
diff --git a/contrib/libs/icu/i18n/fphdlimp.h b/contrib/libs/icu/i18n/fphdlimp.h
index b9fa9b2181..5a5bd06515 100644
--- a/contrib/libs/icu/i18n/fphdlimp.h
+++ b/contrib/libs/icu/i18n/fphdlimp.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -10,13 +10,13 @@
#ifndef FPHDLIMP_H
#define FPHDLIMP_H
-#include "unicode/utypes.h"
-
+#include "unicode/utypes.h"
+
#if !UCONFIG_NO_FORMATTING
#include "unicode/fieldpos.h"
#include "unicode/fpositer.h"
-#include "unicode/formattedvalue.h"
+#include "unicode/formattedvalue.h"
U_NAMESPACE_BEGIN
@@ -24,16 +24,16 @@ U_NAMESPACE_BEGIN
// base class, null implementation
class U_I18N_API FieldPositionHandler: public UMemory {
- protected:
- int32_t fShift = 0;
-
+ protected:
+ int32_t fShift = 0;
+
public:
virtual ~FieldPositionHandler();
- 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);
+ 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);
};
@@ -41,65 +41,65 @@ class U_I18N_API FieldPositionHandler: public UMemory {
class FieldPositionOnlyHandler : public FieldPositionHandler {
FieldPosition& pos;
- UBool acceptFirstOnly = FALSE;
- UBool seenFirst = FALSE;
+ UBool acceptFirstOnly = FALSE;
+ UBool seenFirst = FALSE;
public:
FieldPositionOnlyHandler(FieldPosition& pos);
virtual ~FieldPositionOnlyHandler();
- 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;
-
- /**
- * Enable this option to lock in the FieldPosition value after seeing the
- * first occurrence of the field. The default behavior is to take the last
- * occurrence.
- */
- void setAcceptFirstOnly(UBool acceptFirstOnly);
+ 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;
+
+ /**
+ * Enable this option to lock in the FieldPosition value after seeing the
+ * first occurrence of the field. The default behavior is to take the last
+ * occurrence.
+ */
+ void setAcceptFirstOnly(UBool acceptFirstOnly);
};
// utility subclass FieldPositionIteratorHandler
-// exported as U_I18N_API for tests
+// exported as U_I18N_API for tests
-class U_I18N_API FieldPositionIteratorHandler : public FieldPositionHandler {
+class U_I18N_API FieldPositionIteratorHandler : public FieldPositionHandler {
FieldPositionIterator* iter; // can be NULL
UVector32* vec;
UErrorCode status;
- UFieldCategory fCategory;
+ UFieldCategory fCategory;
// Note, we keep a reference to status, so if status is on the stack, we have
// to be destroyed before status goes out of scope. Easiest thing is to
// allocate us on the stack in the same (or narrower) scope as status has.
// This attempts to encourage that by blocking heap allocation.
- static void* U_EXPORT2 operator new(size_t) U_NOEXCEPT = delete;
- static void* U_EXPORT2 operator new[](size_t) U_NOEXCEPT = delete;
-#if U_HAVE_PLACEMENT_NEW
- static void* U_EXPORT2 operator new(size_t, void*) U_NOEXCEPT = delete;
-#endif
+ static void* U_EXPORT2 operator new(size_t) U_NOEXCEPT = delete;
+ static void* U_EXPORT2 operator new[](size_t) U_NOEXCEPT = delete;
+#if U_HAVE_PLACEMENT_NEW
+ static void* U_EXPORT2 operator new(size_t, void*) U_NOEXCEPT = delete;
+#endif
public:
FieldPositionIteratorHandler(FieldPositionIterator* posIter, UErrorCode& status);
- /** If using this constructor, you must call getError() when done formatting! */
- FieldPositionIteratorHandler(UVector32* vec, UErrorCode& status);
+ /** If using this constructor, you must call getError() when done formatting! */
+ FieldPositionIteratorHandler(UVector32* vec, UErrorCode& status);
~FieldPositionIteratorHandler();
- 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;
-
- /** Copies a failed error code into _status. */
- inline void getError(UErrorCode& _status) {
- if (U_SUCCESS(_status) && U_FAILURE(status)) {
- _status = status;
- }
- }
-
- inline void setCategory(UFieldCategory category) {
- fCategory = category;
- }
+ 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;
+
+ /** Copies a failed error code into _status. */
+ inline void getError(UErrorCode& _status) {
+ if (U_SUCCESS(_status) && U_FAILURE(status)) {
+ _status = status;
+ }
+ }
+
+ inline void setCategory(UFieldCategory category) {
+ fCategory = category;
+ }
};
U_NAMESPACE_END
diff --git a/contrib/libs/icu/i18n/fpositer.cpp b/contrib/libs/icu/i18n/fpositer.cpp
index 75d529eb8c..cf8cffe924 100644
--- a/contrib/libs/icu/i18n/fpositer.cpp
+++ b/contrib/libs/icu/i18n/fpositer.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
@@ -65,10 +65,10 @@ void FieldPositionIterator::setData(UVector32 *adopt, UErrorCode& status) {
if (adopt->size() == 0) {
delete adopt;
adopt = NULL;
- } else if ((adopt->size() % 4) != 0) {
+ } else if ((adopt->size() % 4) != 0) {
status = U_ILLEGAL_ARGUMENT_ERROR;
} else {
- for (int i = 2; i < adopt->size(); i += 4) {
+ for (int i = 2; i < adopt->size(); i += 4) {
if (adopt->elementAti(i) >= adopt->elementAti(i+1)) {
status = U_ILLEGAL_ARGUMENT_ERROR;
break;
@@ -95,8 +95,8 @@ UBool FieldPositionIterator::next(FieldPosition& fp) {
return FALSE;
}
- // Ignore the first element of the tetrad: used for field category
- pos++;
+ // Ignore the first element of the tetrad: used for field category
+ pos++;
fp.setField(data->elementAti(pos++));
fp.setBeginIndex(data->elementAti(pos++));
fp.setEndIndex(data->elementAti(pos++));
diff --git a/contrib/libs/icu/i18n/funcrepl.cpp b/contrib/libs/icu/i18n/funcrepl.cpp
index 7dd54ed8d2..b754950cad 100644
--- a/contrib/libs/icu/i18n/funcrepl.cpp
+++ b/contrib/libs/icu/i18n/funcrepl.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -59,7 +59,7 @@ FunctionReplacer::~FunctionReplacer() {
/**
* Implement UnicodeFunctor
*/
-FunctionReplacer* FunctionReplacer::clone() const {
+FunctionReplacer* FunctionReplacer::clone() const {
return new FunctionReplacer(*this);
}
diff --git a/contrib/libs/icu/i18n/funcrepl.h b/contrib/libs/icu/i18n/funcrepl.h
index fe41f6caaa..ffab79a271 100644
--- a/contrib/libs/icu/i18n/funcrepl.h
+++ b/contrib/libs/icu/i18n/funcrepl.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -70,7 +70,7 @@ class FunctionReplacer : public UnicodeFunctor, public UnicodeReplacer {
/**
* Implement UnicodeFunctor
*/
- virtual FunctionReplacer* clone() const;
+ virtual FunctionReplacer* clone() const;
/**
* UnicodeFunctor API. Cast 'this' to a UnicodeReplacer* pointer
diff --git a/contrib/libs/icu/i18n/gender.cpp b/contrib/libs/icu/i18n/gender.cpp
index dc5def6ad3..15dfc95b86 100644
--- a/contrib/libs/icu/i18n/gender.cpp
+++ b/contrib/libs/icu/i18n/gender.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -32,7 +32,7 @@
#include "uhash.h"
static UHashtable* gGenderInfoCache = NULL;
-
+
static const char* gNeutralStr = "neutral";
static const char* gMailTaintsStr = "maleTaints";
static const char* gMixedNeutralStr = "mixedNeutral";
@@ -98,7 +98,7 @@ const GenderInfo* GenderInfo::getInstance(const Locale& locale, UErrorCode& stat
return NULL;
}
- static UMutex gGenderMetaLock;
+ static UMutex gGenderMetaLock;
const GenderInfo* result = NULL;
const char* key = locale.getName();
{
@@ -160,7 +160,7 @@ const GenderInfo* GenderInfo::loadInstance(const Locale& locale, UErrorCode& sta
if (s == NULL) {
return &gObjs[NEUTRAL];
}
- char type_str[256] = "";
+ char type_str[256] = "";
u_UCharsToChars(s, type_str, resLen + 1);
if (uprv_strcmp(type_str, gNeutralStr) == 0) {
return &gObjs[NEUTRAL];
diff --git a/contrib/libs/icu/i18n/gregocal.cpp b/contrib/libs/icu/i18n/gregocal.cpp
index 6b15171c12..8af8af0e0c 100644
--- a/contrib/libs/icu/i18n/gregocal.cpp
+++ b/contrib/libs/icu/i18n/gregocal.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -286,7 +286,7 @@ fIsGregorian(source.fIsGregorian), fInvertGregorian(source.fInvertGregorian)
// -------------------------------------
-GregorianCalendar* GregorianCalendar::clone() const
+GregorianCalendar* GregorianCalendar::clone() const
{
return new GregorianCalendar(*this);
}
@@ -330,20 +330,20 @@ GregorianCalendar::setGregorianChange(UDate date, UErrorCode& status)
// normalized cutover is in pure date milliseconds; it contains no time
// of day or timezone component, and it used to compare against other
// pure date values.
- double cutoverDay = ClockMath::floorDivide(date, (double)kOneDay);
-
- // Handle the rare case of numeric overflow where the user specifies a time
- // outside of INT32_MIN .. INT32_MAX number of days.
-
- if (cutoverDay <= INT32_MIN) {
- cutoverDay = INT32_MIN;
- fGregorianCutover = fNormalizedGregorianCutover = cutoverDay * kOneDay;
- } else if (cutoverDay >= INT32_MAX) {
- cutoverDay = INT32_MAX;
- fGregorianCutover = fNormalizedGregorianCutover = cutoverDay * kOneDay;
- } else {
- fNormalizedGregorianCutover = cutoverDay * kOneDay;
- fGregorianCutover = date;
+ double cutoverDay = ClockMath::floorDivide(date, (double)kOneDay);
+
+ // Handle the rare case of numeric overflow where the user specifies a time
+ // outside of INT32_MIN .. INT32_MAX number of days.
+
+ if (cutoverDay <= INT32_MIN) {
+ cutoverDay = INT32_MIN;
+ fGregorianCutover = fNormalizedGregorianCutover = cutoverDay * kOneDay;
+ } else if (cutoverDay >= INT32_MAX) {
+ cutoverDay = INT32_MAX;
+ fGregorianCutover = fNormalizedGregorianCutover = cutoverDay * kOneDay;
+ } else {
+ fNormalizedGregorianCutover = cutoverDay * kOneDay;
+ fGregorianCutover = date;
}
// Normalize the year so BC values are represented as 0 and negative
@@ -360,7 +360,7 @@ GregorianCalendar::setGregorianChange(UDate date, UErrorCode& status)
fGregorianCutoverYear = cal->get(UCAL_YEAR, status);
if (cal->get(UCAL_ERA, status) == BC)
fGregorianCutoverYear = 1 - fGregorianCutoverYear;
- fCutoverJulianDay = (int32_t)cutoverDay;
+ fCutoverJulianDay = (int32_t)cutoverDay;
delete cal;
}
@@ -541,8 +541,8 @@ int32_t GregorianCalendar::handleComputeMonthStart(int32_t eyear, int32_t month,
}
UBool isLeap = eyear%4 == 0;
- int64_t y = (int64_t)eyear-1;
- int64_t julianDay = 365*y + ClockMath::floorDivide(y, (int64_t)4) + (kJan1_1JulianDay - 3);
+ int64_t y = (int64_t)eyear-1;
+ int64_t julianDay = 365*y + ClockMath::floorDivide(y, (int64_t)4) + (kJan1_1JulianDay - 3);
nonConstThis->fIsGregorian = (eyear >= fGregorianCutoverYear);
#if defined (U_DEBUG_CAL)
@@ -572,7 +572,7 @@ int32_t GregorianCalendar::handleComputeMonthStart(int32_t eyear, int32_t month,
julianDay += isLeap?kLeapNumDays[month]:kNumDays[month];
}
- return static_cast<int32_t>(julianDay);
+ return static_cast<int32_t>(julianDay);
}
int32_t GregorianCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const
diff --git a/contrib/libs/icu/i18n/gregoimp.cpp b/contrib/libs/icu/i18n/gregoimp.cpp
index 537aa19d8a..f11d52ba5c 100644
--- a/contrib/libs/icu/i18n/gregoimp.cpp
+++ b/contrib/libs/icu/i18n/gregoimp.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -27,11 +27,11 @@ int32_t ClockMath::floorDivide(int32_t numerator, int32_t denominator) {
numerator / denominator : ((numerator + 1) / denominator) - 1;
}
-int64_t ClockMath::floorDivide(int64_t numerator, int64_t denominator) {
- return (numerator >= 0) ?
- numerator / denominator : ((numerator + 1) / denominator) - 1;
-}
-
+int64_t ClockMath::floorDivide(int64_t numerator, int64_t denominator) {
+ return (numerator >= 0) ?
+ numerator / denominator : ((numerator + 1) / denominator) - 1;
+}
+
int32_t ClockMath::floorDivide(double numerator, int32_t denominator,
int32_t& remainder) {
double quotient;
diff --git a/contrib/libs/icu/i18n/gregoimp.h b/contrib/libs/icu/i18n/gregoimp.h
index 06eb323845..fee1ab3096 100644
--- a/contrib/libs/icu/i18n/gregoimp.h
+++ b/contrib/libs/icu/i18n/gregoimp.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -41,17 +41,17 @@ class ClockMath {
static int32_t floorDivide(int32_t numerator, int32_t denominator);
/**
- * Divide two integers, returning the floor of the quotient.
- * Unlike the built-in division, this is mathematically
- * well-behaved. E.g., <code>-1/4</code> => 0 but
- * <code>floorDivide(-1,4)</code> => -1.
- * @param numerator the numerator
- * @param denominator a divisor which must be != 0
- * @return the floor of the quotient
- */
- static int64_t floorDivide(int64_t numerator, int64_t denominator);
-
- /**
+ * Divide two integers, returning the floor of the quotient.
+ * Unlike the built-in division, this is mathematically
+ * well-behaved. E.g., <code>-1/4</code> => 0 but
+ * <code>floorDivide(-1,4)</code> => -1.
+ * @param numerator the numerator
+ * @param denominator a divisor which must be != 0
+ * @return the floor of the quotient
+ */
+ static int64_t floorDivide(int64_t numerator, int64_t denominator);
+
+ /**
* Divide two numbers, returning the floor of the quotient.
* Unlike the built-in division, this is mathematically
* well-behaved. E.g., <code>-1/4</code> => 0 but
@@ -299,8 +299,8 @@ inline int32_t Grego::millisToJulianDay(double millis) {
}
inline int32_t Grego::gregorianShift(int32_t eyear) {
- int64_t y = (int64_t)eyear-1;
- int32_t gregShift = static_cast<int32_t>(ClockMath::floorDivide(y, (int64_t)400) - ClockMath::floorDivide(y, (int64_t)100) + 2);
+ int64_t y = (int64_t)eyear-1;
+ int32_t gregShift = static_cast<int32_t>(ClockMath::floorDivide(y, (int64_t)400) - ClockMath::floorDivide(y, (int64_t)100) + 2);
return gregShift;
}
diff --git a/contrib/libs/icu/i18n/hebrwcal.cpp b/contrib/libs/icu/i18n/hebrwcal.cpp
index c8fb8a1679..9a1a3ab353 100644
--- a/contrib/libs/icu/i18n/hebrwcal.cpp
+++ b/contrib/libs/icu/i18n/hebrwcal.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
@@ -169,7 +169,7 @@ const char *HebrewCalendar::getType() const {
return "hebrew";
}
-HebrewCalendar* HebrewCalendar::clone() const {
+HebrewCalendar* HebrewCalendar::clone() const {
return new HebrewCalendar(*this);
}
diff --git a/contrib/libs/icu/i18n/hebrwcal.h b/contrib/libs/icu/i18n/hebrwcal.h
index 08136de32a..ef2670bdc8 100644
--- a/contrib/libs/icu/i18n/hebrwcal.h
+++ b/contrib/libs/icu/i18n/hebrwcal.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
@@ -192,7 +192,7 @@ public:
* @return return a polymorphic copy of this calendar.
* @internal
*/
- virtual HebrewCalendar* clone() const;
+ virtual HebrewCalendar* clone() const;
public:
/**
diff --git a/contrib/libs/icu/i18n/indiancal.cpp b/contrib/libs/icu/i18n/indiancal.cpp
index f1ab853b94..f66b44ffa7 100644
--- a/contrib/libs/icu/i18n/indiancal.cpp
+++ b/contrib/libs/icu/i18n/indiancal.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
* Copyright (C) 2003-2014, International Business Machines Corporation
@@ -35,7 +35,7 @@ U_NAMESPACE_BEGIN
//-------------------------------------------------------------------------
-IndianCalendar* IndianCalendar::clone() const {
+IndianCalendar* IndianCalendar::clone() const {
return new IndianCalendar(*this);
}
@@ -348,14 +348,14 @@ IndianCalendar::inDaylightTime(UErrorCode& status) const
}
-/**
- * The system maintains a static default century start date and Year. They are
- * initialized the first time they are used. Once the system default century date
- * and year are set, they do not change.
- */
-static UDate gSystemDefaultCenturyStart = DBL_MIN;
-static int32_t gSystemDefaultCenturyStartYear = -1;
-static icu::UInitOnce gSystemDefaultCenturyInit = U_INITONCE_INITIALIZER;
+/**
+ * The system maintains a static default century start date and Year. They are
+ * initialized the first time they are used. Once the system default century date
+ * and year are set, they do not change.
+ */
+static UDate gSystemDefaultCenturyStart = DBL_MIN;
+static int32_t gSystemDefaultCenturyStartYear = -1;
+static icu::UInitOnce gSystemDefaultCenturyInit = U_INITONCE_INITIALIZER;
UBool IndianCalendar::haveDefaultCentury() const
@@ -363,43 +363,43 @@ UBool IndianCalendar::haveDefaultCentury() const
return TRUE;
}
-static void U_CALLCONV
-initializeSystemDefaultCentury()
+static void U_CALLCONV
+initializeSystemDefaultCentury()
{
- // initialize systemDefaultCentury and systemDefaultCenturyYear based
- // on the current time. They'll be set to 80 years before
- // the current time.
- UErrorCode status = U_ZERO_ERROR;
-
- IndianCalendar calendar ( Locale ( "@calendar=Indian" ), status);
- if ( U_SUCCESS ( status ) ) {
- calendar.setTime ( Calendar::getNow(), status );
- calendar.add ( UCAL_YEAR, -80, status );
-
- UDate newStart = calendar.getTime ( status );
- int32_t newYear = calendar.get ( UCAL_YEAR, status );
-
- gSystemDefaultCenturyStart = newStart;
- gSystemDefaultCenturyStartYear = newYear;
- }
- // We have no recourse upon failure.
+ // initialize systemDefaultCentury and systemDefaultCenturyYear based
+ // on the current time. They'll be set to 80 years before
+ // the current time.
+ UErrorCode status = U_ZERO_ERROR;
+
+ IndianCalendar calendar ( Locale ( "@calendar=Indian" ), status);
+ if ( U_SUCCESS ( status ) ) {
+ calendar.setTime ( Calendar::getNow(), status );
+ calendar.add ( UCAL_YEAR, -80, status );
+
+ UDate newStart = calendar.getTime ( status );
+ int32_t newYear = calendar.get ( UCAL_YEAR, status );
+
+ gSystemDefaultCenturyStart = newStart;
+ gSystemDefaultCenturyStartYear = newYear;
+ }
+ // We have no recourse upon failure.
}
-
+
UDate
-IndianCalendar::defaultCenturyStart() const
+IndianCalendar::defaultCenturyStart() const
{
// lazy-evaluate systemDefaultCenturyStart
- umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
- return gSystemDefaultCenturyStart;
+ umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
+ return gSystemDefaultCenturyStart;
}
int32_t
-IndianCalendar::defaultCenturyStartYear() const
+IndianCalendar::defaultCenturyStartYear() const
{
// lazy-evaluate systemDefaultCenturyStartYear
- umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
- return gSystemDefaultCenturyStartYear;
+ umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
+ return gSystemDefaultCenturyStartYear;
}
diff --git a/contrib/libs/icu/i18n/indiancal.h b/contrib/libs/icu/i18n/indiancal.h
index e259d9bc17..e7eaa77fbe 100644
--- a/contrib/libs/icu/i18n/indiancal.h
+++ b/contrib/libs/icu/i18n/indiancal.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*****************************************************************************
@@ -68,7 +68,7 @@ U_NAMESPACE_BEGIN
*/
-class U_I18N_API IndianCalendar : public Calendar {
+class U_I18N_API IndianCalendar : public Calendar {
public:
/**
* Useful constants for IndianCalendar.
@@ -186,7 +186,7 @@ public:
// TODO: copy c'tor, etc
// clone
- virtual IndianCalendar* clone() const;
+ virtual IndianCalendar* clone() const;
private:
/**
@@ -274,10 +274,10 @@ public:
* @return The class ID for all objects of this class.
* @internal
*/
- static UClassID U_EXPORT2 getStaticClassID(void);
+ static UClassID U_EXPORT2 getStaticClassID(void);
/**
- * return the calendar type, "indian".
+ * return the calendar type, "indian".
*
* @return calendar type
* @internal
diff --git a/contrib/libs/icu/i18n/inputext.cpp b/contrib/libs/icu/i18n/inputext.cpp
index 2d4f8a388a..d2f9af10d1 100644
--- a/contrib/libs/icu/i18n/inputext.cpp
+++ b/contrib/libs/icu/i18n/inputext.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
diff --git a/contrib/libs/icu/i18n/inputext.h b/contrib/libs/icu/i18n/inputext.h
index 8edc561fc6..efedf3b68d 100644
--- a/contrib/libs/icu/i18n/inputext.h
+++ b/contrib/libs/icu/i18n/inputext.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
diff --git a/contrib/libs/icu/i18n/islamcal.cpp b/contrib/libs/icu/i18n/islamcal.cpp
index 582b3365a6..77f70faff0 100644
--- a/contrib/libs/icu/i18n/islamcal.cpp
+++ b/contrib/libs/icu/i18n/islamcal.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
@@ -222,12 +222,12 @@ const char *IslamicCalendar::getType() const {
sType = "islamic-umalqura";
break;
default:
- UPRV_UNREACHABLE; // out of range
+ UPRV_UNREACHABLE; // out of range
}
return sType;
}
-IslamicCalendar* IslamicCalendar::clone() const {
+IslamicCalendar* IslamicCalendar::clone() const {
return new IslamicCalendar(*this);
}
@@ -470,7 +470,7 @@ double IslamicCalendar::moonAge(UDate time, UErrorCode &status)
{
double age = 0;
- static UMutex astroLock; // pod bay door lock
+ static UMutex astroLock; // pod bay door lock
umtx_lock(&astroLock);
if(gIslamicCalendarAstro == NULL) {
gIslamicCalendarAstro = new CalendarAstronomer();
@@ -612,7 +612,7 @@ void IslamicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status)
days = julianDay - ASTRONOMICAL_EPOC;
}
// Use the civil calendar approximation, which is just arithmetic
- year = (int32_t)ClockMath::floorDivide(30 * (int64_t)days + 10646, (int64_t)10631);
+ year = (int32_t)ClockMath::floorDivide(30 * (int64_t)days + 10646, (int64_t)10631);
month = (int32_t)uprv_ceil((days - 29 - yearStart(year)) / 29.5 );
month = month<11?month:11;
startDate = monthStart(year, month);
@@ -673,7 +673,7 @@ void IslamicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status)
month = m;
}
} else { // invalid 'civil'
- UPRV_UNREACHABLE; // should not get here, out of range
+ UPRV_UNREACHABLE; // should not get here, out of range
}
dayOfMonth = (days - monthStart(year, month)) + 1;
diff --git a/contrib/libs/icu/i18n/islamcal.h b/contrib/libs/icu/i18n/islamcal.h
index fde58478c0..1bf07c6f42 100644
--- a/contrib/libs/icu/i18n/islamcal.h
+++ b/contrib/libs/icu/i18n/islamcal.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
********************************************************************************
@@ -230,7 +230,7 @@ class U_I18N_API IslamicCalendar : public Calendar {
// TODO: copy c'tor, etc
// clone
- virtual IslamicCalendar* clone() const;
+ virtual IslamicCalendar* clone() const;
private:
/**
diff --git a/contrib/libs/icu/i18n/japancal.cpp b/contrib/libs/icu/i18n/japancal.cpp
index 75a248f406..e7ff137f60 100644
--- a/contrib/libs/icu/i18n/japancal.cpp
+++ b/contrib/libs/icu/i18n/japancal.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -16,105 +16,105 @@
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
-#if U_PLATFORM_HAS_WINUWP_API == 0
-#include <stdlib.h> // getenv() is not available in UWP env
-#else
-#ifndef WIN32_LEAN_AND_MEAN
-# define WIN32_LEAN_AND_MEAN
-#endif
-# define VC_EXTRALEAN
-# define NOUSER
-# define NOSERVICE
-# define NOIME
-# define NOMCX
-#include <windows.h>
-#endif
+#if U_PLATFORM_HAS_WINUWP_API == 0
+#include <stdlib.h> // getenv() is not available in UWP env
+#else
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+# define VC_EXTRALEAN
+# define NOUSER
+# define NOSERVICE
+# define NOIME
+# define NOMCX
+#include <windows.h>
+#endif
#include "cmemory.h"
-#include "erarules.h"
+#include "erarules.h"
#include "japancal.h"
#include "unicode/gregocal.h"
#include "umutex.h"
#include "uassert.h"
-#include "ucln_in.h"
-#include "cstring.h"
-
-static icu::EraRules * gJapaneseEraRules = nullptr;
-static icu::UInitOnce gJapaneseEraRulesInitOnce = U_INITONCE_INITIALIZER;
-static int32_t gCurrentEra = 0;
-
-U_CDECL_BEGIN
-static UBool japanese_calendar_cleanup(void) {
- if (gJapaneseEraRules) {
- delete gJapaneseEraRules;
- gJapaneseEraRules = nullptr;
- }
- gCurrentEra = 0;
- gJapaneseEraRulesInitOnce.reset();
- return TRUE;
-}
-U_CDECL_END
+#include "ucln_in.h"
+#include "cstring.h"
+
+static icu::EraRules * gJapaneseEraRules = nullptr;
+static icu::UInitOnce gJapaneseEraRulesInitOnce = U_INITONCE_INITIALIZER;
+static int32_t gCurrentEra = 0;
+
+U_CDECL_BEGIN
+static UBool japanese_calendar_cleanup(void) {
+ if (gJapaneseEraRules) {
+ delete gJapaneseEraRules;
+ gJapaneseEraRules = nullptr;
+ }
+ gCurrentEra = 0;
+ gJapaneseEraRulesInitOnce.reset();
+ return TRUE;
+}
+U_CDECL_END
U_NAMESPACE_BEGIN
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(JapaneseCalendar)
-static const int32_t kGregorianEpoch = 1970; // used as the default value of EXTENDED_YEAR
-static const char* TENTATIVE_ERA_VAR_NAME = "ICU_ENABLE_TENTATIVE_ERA";
-
-
-// Export the following for use by test code.
-UBool JapaneseCalendar::enableTentativeEra() {
- // Although start date of next Japanese era is planned ahead, a name of
- // new era might not be available. This implementation allows tester to
- // check a new era without era names by settings below (in priority order).
- // By default, such tentative era is disabled.
-
- // 1. Environment variable ICU_ENABLE_TENTATIVE_ERA=true or false
-
- UBool includeTentativeEra = FALSE;
-
-#if U_PLATFORM_HAS_WINUWP_API == 1
- // UWP doesn't allow access to getenv(), but we can call GetEnvironmentVariableW to do the same thing.
- UChar varName[26] = {};
- u_charsToUChars(TENTATIVE_ERA_VAR_NAME, varName, static_cast<int32_t>(uprv_strlen(TENTATIVE_ERA_VAR_NAME)));
- WCHAR varValue[5] = {};
- DWORD ret = GetEnvironmentVariableW(reinterpret_cast<WCHAR*>(varName), varValue, UPRV_LENGTHOF(varValue));
- if ((ret == 4) && (_wcsicmp(varValue, L"true") == 0)) {
- includeTentativeEra = TRUE;
- }
-#else
- char *envVarVal = getenv(TENTATIVE_ERA_VAR_NAME);
- if (envVarVal != NULL && uprv_stricmp(envVarVal, "true") == 0) {
- includeTentativeEra = TRUE;
- }
-#endif
- return includeTentativeEra;
-}
-
-
-// Initialize global Japanese era data
-static void U_CALLCONV initializeEras(UErrorCode &status) {
- gJapaneseEraRules = EraRules::createInstance("japanese", JapaneseCalendar::enableTentativeEra(), status);
- if (U_FAILURE(status)) {
- return;
- }
- gCurrentEra = gJapaneseEraRules->getCurrentEraIndex();
-}
-
-static void init(UErrorCode &status) {
- umtx_initOnce(gJapaneseEraRulesInitOnce, &initializeEras, status);
- ucln_i18n_registerCleanup(UCLN_I18N_JAPANESE_CALENDAR, japanese_calendar_cleanup);
-}
-
+static const int32_t kGregorianEpoch = 1970; // used as the default value of EXTENDED_YEAR
+static const char* TENTATIVE_ERA_VAR_NAME = "ICU_ENABLE_TENTATIVE_ERA";
+
+
+// Export the following for use by test code.
+UBool JapaneseCalendar::enableTentativeEra() {
+ // Although start date of next Japanese era is planned ahead, a name of
+ // new era might not be available. This implementation allows tester to
+ // check a new era without era names by settings below (in priority order).
+ // By default, such tentative era is disabled.
+
+ // 1. Environment variable ICU_ENABLE_TENTATIVE_ERA=true or false
+
+ UBool includeTentativeEra = FALSE;
+
+#if U_PLATFORM_HAS_WINUWP_API == 1
+ // UWP doesn't allow access to getenv(), but we can call GetEnvironmentVariableW to do the same thing.
+ UChar varName[26] = {};
+ u_charsToUChars(TENTATIVE_ERA_VAR_NAME, varName, static_cast<int32_t>(uprv_strlen(TENTATIVE_ERA_VAR_NAME)));
+ WCHAR varValue[5] = {};
+ DWORD ret = GetEnvironmentVariableW(reinterpret_cast<WCHAR*>(varName), varValue, UPRV_LENGTHOF(varValue));
+ if ((ret == 4) && (_wcsicmp(varValue, L"true") == 0)) {
+ includeTentativeEra = TRUE;
+ }
+#else
+ char *envVarVal = getenv(TENTATIVE_ERA_VAR_NAME);
+ if (envVarVal != NULL && uprv_stricmp(envVarVal, "true") == 0) {
+ includeTentativeEra = TRUE;
+ }
+#endif
+ return includeTentativeEra;
+}
+
+
+// Initialize global Japanese era data
+static void U_CALLCONV initializeEras(UErrorCode &status) {
+ gJapaneseEraRules = EraRules::createInstance("japanese", JapaneseCalendar::enableTentativeEra(), status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ gCurrentEra = gJapaneseEraRules->getCurrentEraIndex();
+}
+
+static void init(UErrorCode &status) {
+ umtx_initOnce(gJapaneseEraRulesInitOnce, &initializeEras, status);
+ ucln_i18n_registerCleanup(UCLN_I18N_JAPANESE_CALENDAR, japanese_calendar_cleanup);
+}
+
/* Some platforms don't like to export constants, like old Palm OS and some z/OS configurations. */
uint32_t JapaneseCalendar::getCurrentEra() {
- return gCurrentEra;
+ return gCurrentEra;
}
JapaneseCalendar::JapaneseCalendar(const Locale& aLocale, UErrorCode& success)
: GregorianCalendar(aLocale, success)
{
- init(success);
+ init(success);
setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
}
@@ -125,9 +125,9 @@ JapaneseCalendar::~JapaneseCalendar()
JapaneseCalendar::JapaneseCalendar(const JapaneseCalendar& source)
: GregorianCalendar(source)
{
- UErrorCode status = U_ZERO_ERROR;
- init(status);
- U_ASSERT(U_SUCCESS(status));
+ UErrorCode status = U_ZERO_ERROR;
+ init(status);
+ U_ASSERT(U_SUCCESS(status));
}
JapaneseCalendar& JapaneseCalendar::operator= ( const JapaneseCalendar& right)
@@ -136,7 +136,7 @@ JapaneseCalendar& JapaneseCalendar::operator= ( const JapaneseCalendar& right)
return *this;
}
-JapaneseCalendar* JapaneseCalendar::clone() const
+JapaneseCalendar* JapaneseCalendar::clone() const
{
return new JapaneseCalendar(*this);
}
@@ -154,14 +154,14 @@ int32_t JapaneseCalendar::getDefaultMonthInYear(int32_t eyear)
int32_t month = 0;
// Find out if we are at the edge of an era
- int32_t eraStart[3] = { 0,0,0 };
- UErrorCode status = U_ZERO_ERROR;
- gJapaneseEraRules->getStartDate(era, eraStart, status);
- U_ASSERT(U_SUCCESS(status));
- if(eyear == eraStart[0]) {
+ int32_t eraStart[3] = { 0,0,0 };
+ UErrorCode status = U_ZERO_ERROR;
+ gJapaneseEraRules->getStartDate(era, eraStart, status);
+ U_ASSERT(U_SUCCESS(status));
+ if(eyear == eraStart[0]) {
// Yes, we're in the first year of this era.
- return eraStart[1] // month
- -1; // return 0-based month
+ return eraStart[1] // month
+ -1; // return 0-based month
}
return month;
@@ -172,13 +172,13 @@ int32_t JapaneseCalendar::getDefaultDayInMonth(int32_t eyear, int32_t month)
int32_t era = internalGetEra();
int32_t day = 1;
- int32_t eraStart[3] = { 0,0,0 };
- UErrorCode status = U_ZERO_ERROR;
- gJapaneseEraRules->getStartDate(era, eraStart, status);
- U_ASSERT(U_SUCCESS(status));
- if(eyear == eraStart[0]) {
- if(month == eraStart[1] - 1) {
- return eraStart[2];
+ int32_t eraStart[3] = { 0,0,0 };
+ UErrorCode status = U_ZERO_ERROR;
+ gJapaneseEraRules->getStartDate(era, eraStart, status);
+ U_ASSERT(U_SUCCESS(status));
+ if(eyear == eraStart[0]) {
+ if(month == eraStart[1] - 1) {
+ return eraStart[2];
}
}
@@ -188,7 +188,7 @@ int32_t JapaneseCalendar::getDefaultDayInMonth(int32_t eyear, int32_t month)
int32_t JapaneseCalendar::internalGetEra() const
{
- return internalGet(UCAL_ERA, gCurrentEra);
+ return internalGet(UCAL_ERA, gCurrentEra);
}
int32_t JapaneseCalendar::handleGetExtendedYear()
@@ -199,18 +199,18 @@ int32_t JapaneseCalendar::handleGetExtendedYear()
if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR &&
newerField(UCAL_EXTENDED_YEAR, UCAL_ERA) == UCAL_EXTENDED_YEAR) {
- year = internalGet(UCAL_EXTENDED_YEAR, kGregorianEpoch);
- } else {
- UErrorCode status = U_ZERO_ERROR;
- int32_t eraStartYear = gJapaneseEraRules->getStartYear(internalGet(UCAL_ERA, gCurrentEra), status);
- U_ASSERT(U_SUCCESS(status));
-
- // extended year is a gregorian year, where 1 = 1AD, 0 = 1BC, -1 = 2BC, etc
- year = internalGet(UCAL_YEAR, 1) // pin to minimum of year 1 (first year)
- + eraStartYear // add gregorian starting year
- - 1; // Subtract one because year starts at 1
- }
- return year;
+ year = internalGet(UCAL_EXTENDED_YEAR, kGregorianEpoch);
+ } else {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t eraStartYear = gJapaneseEraRules->getStartYear(internalGet(UCAL_ERA, gCurrentEra), status);
+ U_ASSERT(U_SUCCESS(status));
+
+ // extended year is a gregorian year, where 1 = 1AD, 0 = 1BC, -1 = 2BC, etc
+ year = internalGet(UCAL_YEAR, 1) // pin to minimum of year 1 (first year)
+ + eraStartYear // add gregorian starting year
+ - 1; // Subtract one because year starts at 1
+ }
+ return year;
}
@@ -219,10 +219,10 @@ void JapaneseCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status
//Calendar::timeToFields(theTime, quick, status);
GregorianCalendar::handleComputeFields(julianDay, status);
int32_t year = internalGet(UCAL_EXTENDED_YEAR); // Gregorian year
- int32_t eraIdx = gJapaneseEraRules->getEraIndex(year, internalGet(UCAL_MONTH) + 1, internalGet(UCAL_DAY_OF_MONTH), status);
+ int32_t eraIdx = gJapaneseEraRules->getEraIndex(year, internalGet(UCAL_MONTH) + 1, internalGet(UCAL_DAY_OF_MONTH), status);
- internalSet(UCAL_ERA, eraIdx);
- internalSet(UCAL_YEAR, year - gJapaneseEraRules->getStartYear(eraIdx, status) + 1);
+ internalSet(UCAL_ERA, eraIdx);
+ internalSet(UCAL_YEAR, year - gJapaneseEraRules->getStartYear(eraIdx, status) + 1);
}
/*
@@ -250,7 +250,7 @@ int32_t JapaneseCalendar::handleGetLimit(UCalendarDateFields field, ELimitType l
if (limitType == UCAL_LIMIT_MINIMUM || limitType == UCAL_LIMIT_GREATEST_MINIMUM) {
return 0;
}
- return gJapaneseEraRules->getNumberOfEras() - 1; // max known era, not gCurrentEra
+ return gJapaneseEraRules->getNumberOfEras() - 1; // max known era, not gCurrentEra
case UCAL_YEAR:
{
switch (limitType) {
@@ -261,12 +261,12 @@ int32_t JapaneseCalendar::handleGetLimit(UCalendarDateFields field, ELimitType l
return 1;
case UCAL_LIMIT_COUNT: //added to avoid warning
case UCAL_LIMIT_MAXIMUM:
- {
- UErrorCode status = U_ZERO_ERROR;
- int32_t eraStartYear = gJapaneseEraRules->getStartYear(gCurrentEra, status);
- U_ASSERT(U_SUCCESS(status));
- return GregorianCalendar::handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM) - eraStartYear;
- }
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t eraStartYear = gJapaneseEraRules->getStartYear(gCurrentEra, status);
+ U_ASSERT(U_SUCCESS(status));
+ return GregorianCalendar::handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM) - eraStartYear;
+ }
default:
return 1; // Error condition, invalid limitType
}
@@ -282,18 +282,18 @@ int32_t JapaneseCalendar::getActualMaximum(UCalendarDateFields field, UErrorCode
if (U_FAILURE(status)) {
return 0; // error case... any value
}
- if (era == gJapaneseEraRules->getNumberOfEras() - 1) { // max known era, not gCurrentEra
+ if (era == gJapaneseEraRules->getNumberOfEras() - 1) { // max known era, not gCurrentEra
// TODO: Investigate what value should be used here - revisit after 4.0.
return handleGetLimit(UCAL_YEAR, UCAL_LIMIT_MAXIMUM);
} else {
- int32_t nextEraStart[3] = { 0,0,0 };
- gJapaneseEraRules->getStartDate(era + 1, nextEraStart, status);
- int32_t nextEraYear = nextEraStart[0];
- int32_t nextEraMonth = nextEraStart[1]; // 1-base
- int32_t nextEraDate = nextEraStart[2];
-
- int32_t eraStartYear = gJapaneseEraRules->getStartYear(era, status);
- int32_t maxYear = nextEraYear - eraStartYear + 1; // 1-base
+ int32_t nextEraStart[3] = { 0,0,0 };
+ gJapaneseEraRules->getStartDate(era + 1, nextEraStart, status);
+ int32_t nextEraYear = nextEraStart[0];
+ int32_t nextEraMonth = nextEraStart[1]; // 1-base
+ int32_t nextEraDate = nextEraStart[2];
+
+ int32_t eraStartYear = gJapaneseEraRules->getStartYear(era, status);
+ int32_t maxYear = nextEraYear - eraStartYear + 1; // 1-base
if (nextEraMonth == 1 && nextEraDate == 1) {
// Subtract 1, because the next era starts at Jan 1
maxYear--;
diff --git a/contrib/libs/icu/i18n/japancal.h b/contrib/libs/icu/i18n/japancal.h
index 03e6361c9f..f8340b2c40 100644
--- a/contrib/libs/icu/i18n/japancal.h
+++ b/contrib/libs/icu/i18n/japancal.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
********************************************************************************
@@ -49,34 +49,34 @@ U_NAMESPACE_BEGIN
* July 30, 1912 (Taisho), December 25, 1926 (Showa), and January 7, 1989 (Heisei). Constants
* for these eras, suitable for use in the <code>UCAL_ERA</code> field, are provided
* in this class. Note that the <em>number</em> used for each era is more or
- * less arbitrary. Currently, the era starting in 645 AD is era #0; however this
- * may change in the future. Use the predefined constants rather than using actual,
- * absolute numbers.
+ * less arbitrary. Currently, the era starting in 645 AD is era #0; however this
+ * may change in the future. Use the predefined constants rather than using actual,
+ * absolute numbers.
* <p>
- * Since ICU4C 63, start date of each era is imported from CLDR. CLDR era data
- * may contain tentative era in near future with placeholder names. By default,
- * such era data is not enabled. ICU4C users who want to test the behavior of
- * the future era can enable this one of following settings (in the priority
- * order):
- * <ol>
- * <li>Environment variable <code>ICU_ENABLE_TENTATIVE_ERA=true</code>.</li>
- * </nl>
+ * Since ICU4C 63, start date of each era is imported from CLDR. CLDR era data
+ * may contain tentative era in near future with placeholder names. By default,
+ * such era data is not enabled. ICU4C users who want to test the behavior of
+ * the future era can enable this one of following settings (in the priority
+ * order):
+ * <ol>
+ * <li>Environment variable <code>ICU_ENABLE_TENTATIVE_ERA=true</code>.</li>
+ * </nl>
* @internal
*/
class JapaneseCalendar : public GregorianCalendar {
public:
/**
- * Check environment variable.
- * @internal
- */
- U_I18N_API static UBool U_EXPORT2 enableTentativeEra(void);
-
- /**
- * Useful constants for JapaneseCalendar.
- * Exported for use by test code.
+ * Check environment variable.
* @internal
*/
+ U_I18N_API static UBool U_EXPORT2 enableTentativeEra(void);
+
+ /**
+ * Useful constants for JapaneseCalendar.
+ * Exported for use by test code.
+ * @internal
+ */
U_I18N_API static uint32_t U_EXPORT2 getCurrentEra(void); // the current era
/**
@@ -116,7 +116,7 @@ public:
* @return return a polymorphic copy of this calendar.
* @internal
*/
- virtual JapaneseCalendar* clone() const;
+ virtual JapaneseCalendar* clone() const;
/**
* Return the extended year defined by the current fields. In the
diff --git a/contrib/libs/icu/i18n/listformatter.cpp b/contrib/libs/icu/i18n/listformatter.cpp
index da99c9291d..60c2bcef42 100644
--- a/contrib/libs/icu/i18n/listformatter.cpp
+++ b/contrib/libs/icu/i18n/listformatter.cpp
@@ -1,808 +1,808 @@
-// © 2016 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html
-/*
-*******************************************************************************
-*
-* Copyright (C) 2013-2016, International Business Machines
-* Corporation and others. All Rights Reserved.
-*
-*******************************************************************************
-* file name: listformatter.cpp
-* encoding: UTF-8
-* tab size: 8 (not used)
-* indentation:4
-*
-* created on: 2012aug27
-* created by: Umesh P. Nair
-*/
-
-#include "cmemory.h"
-#include "unicode/fpositer.h" // FieldPositionIterator
-#include "unicode/listformatter.h"
-#include "unicode/simpleformatter.h"
-#include "unicode/ulistformatter.h"
-#include "unicode/uscript.h"
-#include "fphdlimp.h"
-#include "mutex.h"
-#include "hash.h"
-#include "cstring.h"
-#include "uarrsort.h"
-#include "ulocimp.h"
-#include "charstr.h"
-#include "ucln_in.h"
-#include "uresimp.h"
-#include "resource.h"
-#include "formattedval_impl.h"
-
-U_NAMESPACE_BEGIN
-
-namespace {
-
-class PatternHandler : public UObject {
-public:
- PatternHandler(const UnicodeString& two, const UnicodeString& end, UErrorCode& errorCode) :
- twoPattern(two, 2, 2, errorCode),
- endPattern(end, 2, 2, errorCode) { }
-
- PatternHandler(const SimpleFormatter& two, const SimpleFormatter& end) :
- twoPattern(two),
- endPattern(end) { }
-
- virtual ~PatternHandler();
-
- virtual PatternHandler* clone() const { return new PatternHandler(twoPattern, endPattern); }
-
- virtual const SimpleFormatter& getTwoPattern(const UnicodeString&) const {
- return twoPattern;
- }
-
- virtual const SimpleFormatter& getEndPattern(const UnicodeString&) const {
- return endPattern;
- }
-
-protected:
- SimpleFormatter twoPattern;
- SimpleFormatter endPattern;
-};
-
-PatternHandler::~PatternHandler() {
-}
-
-class ContextualHandler : public PatternHandler {
-public:
- ContextualHandler(bool (*testFunc)(const UnicodeString& text),
- const UnicodeString& thenTwo,
- const UnicodeString& elseTwo,
- const UnicodeString& thenEnd,
- const UnicodeString& elseEnd,
- UErrorCode& errorCode) :
- PatternHandler(elseTwo, elseEnd, errorCode),
- test(testFunc),
- thenTwoPattern(thenTwo, 2, 2, errorCode),
- thenEndPattern(thenEnd, 2, 2, errorCode) { }
-
- ContextualHandler(bool (*testFunc)(const UnicodeString& text),
- const SimpleFormatter& thenTwo, SimpleFormatter elseTwo,
- const SimpleFormatter& thenEnd, SimpleFormatter elseEnd) :
- PatternHandler(elseTwo, elseEnd),
- test(testFunc),
- thenTwoPattern(thenTwo),
- thenEndPattern(thenEnd) { }
-
- ~ContextualHandler() override;
-
- PatternHandler* clone() const override {
- return new ContextualHandler(
- test, thenTwoPattern, twoPattern, thenEndPattern, endPattern);
- }
-
- const SimpleFormatter& getTwoPattern(
- const UnicodeString& text) const override {
- return (test)(text) ? thenTwoPattern : twoPattern;
- }
-
- const SimpleFormatter& getEndPattern(
- const UnicodeString& text) const override {
- return (test)(text) ? thenEndPattern : endPattern;
- }
-
-private:
- bool (*test)(const UnicodeString&);
- SimpleFormatter thenTwoPattern;
- SimpleFormatter thenEndPattern;
-};
-
-ContextualHandler::~ContextualHandler() {
-}
-
-static const char16_t *spanishY = u"{0} y {1}";
-static const char16_t *spanishE = u"{0} e {1}";
-static const char16_t *spanishO = u"{0} o {1}";
-static const char16_t *spanishU = u"{0} u {1}";
-static const char16_t *hebrewVav = u"{0} \u05D5{1}";
-static const char16_t *hebrewVavDash = u"{0} \u05D5-{1}";
-
-// Condiction to change to e.
-// Starts with "hi" or "i" but not with "hie" nor "hia"
-static bool shouldChangeToE(const UnicodeString& text) {
- int32_t len = text.length();
- if (len == 0) { return false; }
- // Case insensitive match hi but not hie nor hia.
- if ((text[0] == u'h' || text[0] == u'H') &&
- ((len > 1) && (text[1] == u'i' || text[1] == u'I')) &&
- ((len == 2) || !(text[2] == u'a' || text[2] == u'A' || text[2] == u'e' || text[2] == u'E'))) {
- return true;
- }
- // Case insensitive for "start with i"
- if (text[0] == u'i' || text[0] == u'I') { return true; }
- return false;
-}
-
-// Condiction to change to u.
-// Starts with "o", "ho", and "8". Also "11" by itself.
-// re: ^((o|ho|8).*|11)$
-static bool shouldChangeToU(const UnicodeString& text) {
- int32_t len = text.length();
- if (len == 0) { return false; }
- // Case insensitive match o.* and 8.*
- if (text[0] == u'o' || text[0] == u'O' || text[0] == u'8') { return true; }
- // Case insensitive match ho.*
- if ((text[0] == u'h' || text[0] == u'H') &&
- ((len > 1) && (text[1] == 'o' || text[1] == u'O'))) {
- return true;
- }
- // match "^11$" and "^11 .*"
- if ((len >= 2) && text[0] == u'1' && text[1] == u'1' && (len == 2 || text[2] == u' ')) { return true; }
- return false;
-}
-
-// Condiction to change to VAV follow by a dash.
-// Starts with non Hebrew letter.
-static bool shouldChangeToVavDash(const UnicodeString& text) {
- if (text.isEmpty()) { return false; }
- UErrorCode status = U_ZERO_ERROR;
- return uscript_getScript(text.char32At(0), &status) != USCRIPT_HEBREW;
-}
-
-PatternHandler* createPatternHandler(
- const char* lang, const UnicodeString& two, const UnicodeString& end,
- UErrorCode& status) {
- if (uprv_strcmp(lang, "es") == 0) {
- // Spanish
- UnicodeString spanishYStr(TRUE, spanishY, -1);
- bool twoIsY = two == spanishYStr;
- bool endIsY = end == spanishYStr;
- if (twoIsY || endIsY) {
- UnicodeString replacement(TRUE, spanishE, -1);
- return new ContextualHandler(
- shouldChangeToE,
- twoIsY ? replacement : two, two,
- endIsY ? replacement : end, end, status);
- }
- UnicodeString spanishOStr(TRUE, spanishO, -1);
- bool twoIsO = two == spanishOStr;
- bool endIsO = end == spanishOStr;
- if (twoIsO || endIsO) {
- UnicodeString replacement(TRUE, spanishU, -1);
- return new ContextualHandler(
- shouldChangeToU,
- twoIsO ? replacement : two, two,
- endIsO ? replacement : end, end, status);
- }
- } else if (uprv_strcmp(lang, "he") == 0 || uprv_strcmp(lang, "iw") == 0) {
- // Hebrew
- UnicodeString hebrewVavStr(TRUE, hebrewVav, -1);
- bool twoIsVav = two == hebrewVavStr;
- bool endIsVav = end == hebrewVavStr;
- if (twoIsVav || endIsVav) {
- UnicodeString replacement(TRUE, hebrewVavDash, -1);
- return new ContextualHandler(
- shouldChangeToVavDash,
- twoIsVav ? replacement : two, two,
- endIsVav ? replacement : end, end, status);
- }
- }
- return new PatternHandler(two, end, status);
-}
-
-} // namespace
-
-struct ListFormatInternal : public UMemory {
- SimpleFormatter startPattern;
- SimpleFormatter middlePattern;
- LocalPointer<PatternHandler> patternHandler;
-
-ListFormatInternal(
- const UnicodeString& two,
- const UnicodeString& start,
- const UnicodeString& middle,
- const UnicodeString& end,
- const Locale& locale,
- UErrorCode &errorCode) :
- startPattern(start, 2, 2, errorCode),
- middlePattern(middle, 2, 2, errorCode),
- patternHandler(createPatternHandler(locale.getLanguage(), two, end, errorCode), errorCode) { }
-
-ListFormatInternal(const ListFormatData &data, UErrorCode &errorCode) :
- startPattern(data.startPattern, errorCode),
- middlePattern(data.middlePattern, errorCode),
- patternHandler(createPatternHandler(
- data.locale.getLanguage(), data.twoPattern, data.endPattern, errorCode), errorCode) { }
-
-ListFormatInternal(const ListFormatInternal &other) :
- startPattern(other.startPattern),
- middlePattern(other.middlePattern),
- patternHandler(other.patternHandler->clone()) { }
-};
-
-
-#if !UCONFIG_NO_FORMATTING
-class FormattedListData : public FormattedValueFieldPositionIteratorImpl {
-public:
- FormattedListData(UErrorCode& status) : FormattedValueFieldPositionIteratorImpl(5, status) {}
- virtual ~FormattedListData();
-};
-
-FormattedListData::~FormattedListData() = default;
-
-UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(FormattedList)
-#endif
-
-
-static Hashtable* listPatternHash = nullptr;
-
-U_CDECL_BEGIN
-static UBool U_CALLCONV uprv_listformatter_cleanup() {
- delete listPatternHash;
- listPatternHash = nullptr;
- return TRUE;
-}
-
-static void U_CALLCONV
-uprv_deleteListFormatInternal(void *obj) {
- delete static_cast<ListFormatInternal *>(obj);
-}
-
-U_CDECL_END
-
-ListFormatter::ListFormatter(const ListFormatter& other) :
- owned(other.owned), data(other.data) {
- if (other.owned != nullptr) {
- owned = new ListFormatInternal(*other.owned);
- data = owned;
- }
-}
-
-ListFormatter& ListFormatter::operator=(const ListFormatter& other) {
- if (this == &other) {
- return *this;
- }
- delete owned;
- if (other.owned) {
- owned = new ListFormatInternal(*other.owned);
- data = owned;
- } else {
- owned = nullptr;
- data = other.data;
- }
- return *this;
-}
-
-void ListFormatter::initializeHash(UErrorCode& errorCode) {
- if (U_FAILURE(errorCode)) {
- return;
- }
-
- listPatternHash = new Hashtable();
- if (listPatternHash == nullptr) {
- errorCode = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
-
- listPatternHash->setValueDeleter(uprv_deleteListFormatInternal);
- ucln_i18n_registerCleanup(UCLN_I18N_LIST_FORMATTER, uprv_listformatter_cleanup);
-
-}
-
-const ListFormatInternal* ListFormatter::getListFormatInternal(
- const Locale& locale, const char *style, UErrorCode& errorCode) {
- if (U_FAILURE(errorCode)) {
- return nullptr;
- }
- CharString keyBuffer(locale.getName(), errorCode);
- keyBuffer.append(':', errorCode).append(style, errorCode);
- UnicodeString key(keyBuffer.data(), -1, US_INV);
- ListFormatInternal* result = nullptr;
- static UMutex listFormatterMutex;
- {
- Mutex m(&listFormatterMutex);
- if (listPatternHash == nullptr) {
- initializeHash(errorCode);
- if (U_FAILURE(errorCode)) {
- return nullptr;
- }
- }
- result = static_cast<ListFormatInternal*>(listPatternHash->get(key));
- }
- if (result != nullptr) {
- return result;
- }
- result = loadListFormatInternal(locale, style, errorCode);
- if (U_FAILURE(errorCode)) {
- return nullptr;
- }
-
- {
- Mutex m(&listFormatterMutex);
- ListFormatInternal* temp = static_cast<ListFormatInternal*>(listPatternHash->get(key));
- if (temp != nullptr) {
- delete result;
- result = temp;
- } else {
- listPatternHash->put(key, result, errorCode);
- if (U_FAILURE(errorCode)) {
- return nullptr;
- }
- }
- }
- return result;
-}
-
-#if !UCONFIG_NO_FORMATTING
-static const char* typeWidthToStyleString(UListFormatterType type, UListFormatterWidth width) {
- switch (type) {
- case ULISTFMT_TYPE_AND:
- switch (width) {
- case ULISTFMT_WIDTH_WIDE:
- return "standard";
- case ULISTFMT_WIDTH_SHORT:
- return "standard-short";
- case ULISTFMT_WIDTH_NARROW:
- return "standard-narrow";
- default:
- return nullptr;
- }
- break;
-
- case ULISTFMT_TYPE_OR:
- switch (width) {
- case ULISTFMT_WIDTH_WIDE:
- return "or";
- case ULISTFMT_WIDTH_SHORT:
- return "or-short";
- case ULISTFMT_WIDTH_NARROW:
- return "or-narrow";
- default:
- return nullptr;
- }
- break;
-
- case ULISTFMT_TYPE_UNITS:
- switch (width) {
- case ULISTFMT_WIDTH_WIDE:
- return "unit";
- case ULISTFMT_WIDTH_SHORT:
- return "unit-short";
- case ULISTFMT_WIDTH_NARROW:
- return "unit-narrow";
- default:
- return nullptr;
- }
- }
-
- return nullptr;
-}
-#endif
-
-static const UChar solidus = 0x2F;
-static const UChar aliasPrefix[] = { 0x6C,0x69,0x73,0x74,0x50,0x61,0x74,0x74,0x65,0x72,0x6E,0x2F }; // "listPattern/"
-enum {
- kAliasPrefixLen = UPRV_LENGTHOF(aliasPrefix),
- kStyleLenMax = 24 // longest currently is 14
-};
-
-struct ListFormatter::ListPatternsSink : public ResourceSink {
- UnicodeString two, start, middle, end;
-#if ((U_PLATFORM == U_PF_AIX) || (U_PLATFORM == U_PF_OS390)) && (U_CPLUSPLUS_VERSION < 11)
- char aliasedStyle[kStyleLenMax+1];
- ListPatternsSink() {
- uprv_memset(aliasedStyle, 0, kStyleLenMax+1);
- }
-#else
- char aliasedStyle[kStyleLenMax+1] = {0};
-
- ListPatternsSink() {}
-#endif
- virtual ~ListPatternsSink();
-
- void setAliasedStyle(UnicodeString alias) {
- int32_t startIndex = alias.indexOf(aliasPrefix, kAliasPrefixLen, 0);
- if (startIndex < 0) {
- return;
- }
- startIndex += kAliasPrefixLen;
- int32_t endIndex = alias.indexOf(solidus, startIndex);
- if (endIndex < 0) {
- endIndex = alias.length();
- }
- alias.extract(startIndex, endIndex-startIndex, aliasedStyle, kStyleLenMax+1, US_INV);
- aliasedStyle[kStyleLenMax] = 0;
- }
-
- void handleValueForPattern(ResourceValue &value, UnicodeString &pattern, UErrorCode &errorCode) {
- if (pattern.isEmpty()) {
- if (value.getType() == URES_ALIAS) {
- if (aliasedStyle[0] == 0) {
- setAliasedStyle(value.getAliasUnicodeString(errorCode));
- }
- } else {
- pattern = value.getUnicodeString(errorCode);
- }
- }
- }
-
- virtual void put(const char *key, ResourceValue &value, UBool /*noFallback*/,
- UErrorCode &errorCode) {
- aliasedStyle[0] = 0;
- if (value.getType() == URES_ALIAS) {
- setAliasedStyle(value.getAliasUnicodeString(errorCode));
- return;
- }
- ResourceTable listPatterns = value.getTable(errorCode);
- for (int i = 0; U_SUCCESS(errorCode) && listPatterns.getKeyAndValue(i, key, value); ++i) {
- if (uprv_strcmp(key, "2") == 0) {
- handleValueForPattern(value, two, errorCode);
- } else if (uprv_strcmp(key, "end") == 0) {
- handleValueForPattern(value, end, errorCode);
- } else if (uprv_strcmp(key, "middle") == 0) {
- handleValueForPattern(value, middle, errorCode);
- } else if (uprv_strcmp(key, "start") == 0) {
- handleValueForPattern(value, start, errorCode);
- }
- }
- }
-};
-
-// Virtual destructors must be defined out of line.
-ListFormatter::ListPatternsSink::~ListPatternsSink() {}
-
-ListFormatInternal* ListFormatter::loadListFormatInternal(
- const Locale& locale, const char * style, UErrorCode& errorCode) {
- UResourceBundle* rb = ures_open(nullptr, locale.getName(), &errorCode);
- rb = ures_getByKeyWithFallback(rb, "listPattern", rb, &errorCode);
- if (U_FAILURE(errorCode)) {
- ures_close(rb);
- return nullptr;
- }
- ListFormatter::ListPatternsSink sink;
- char currentStyle[kStyleLenMax+1];
- uprv_strncpy(currentStyle, style, kStyleLenMax);
- currentStyle[kStyleLenMax] = 0;
-
- for (;;) {
- ures_getAllItemsWithFallback(rb, currentStyle, sink, errorCode);
- if (U_FAILURE(errorCode) || sink.aliasedStyle[0] == 0 || uprv_strcmp(currentStyle, sink.aliasedStyle) == 0) {
- break;
- }
- uprv_strcpy(currentStyle, sink.aliasedStyle);
- }
- ures_close(rb);
- if (U_FAILURE(errorCode)) {
- return nullptr;
- }
- if (sink.two.isEmpty() || sink.start.isEmpty() || sink.middle.isEmpty() || sink.end.isEmpty()) {
- errorCode = U_MISSING_RESOURCE_ERROR;
- return nullptr;
- }
-
- ListFormatInternal* result = new ListFormatInternal(sink.two, sink.start, sink.middle, sink.end, locale, errorCode);
- if (result == nullptr) {
- errorCode = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
- if (U_FAILURE(errorCode)) {
- delete result;
- return nullptr;
- }
- return result;
-}
-
-ListFormatter* ListFormatter::createInstance(UErrorCode& errorCode) {
- Locale locale; // The default locale.
- return createInstance(locale, errorCode);
-}
-
-ListFormatter* ListFormatter::createInstance(const Locale& locale, UErrorCode& errorCode) {
-#if !UCONFIG_NO_FORMATTING
- return createInstance(locale, ULISTFMT_TYPE_AND, ULISTFMT_WIDTH_WIDE, errorCode);
-#else
- return createInstance(locale, "standard", errorCode);
-#endif
-}
-
-#if !UCONFIG_NO_FORMATTING
-ListFormatter* ListFormatter::createInstance(
- const Locale& locale, UListFormatterType type, UListFormatterWidth width, UErrorCode& errorCode) {
- const char* style = typeWidthToStyleString(type, width);
- if (style == nullptr) {
- errorCode = U_ILLEGAL_ARGUMENT_ERROR;
- return nullptr;
- }
- return createInstance(locale, style, errorCode);
-}
-#endif
-
-ListFormatter* ListFormatter::createInstance(const Locale& locale, const char *style, UErrorCode& errorCode) {
- const ListFormatInternal* listFormatInternal = getListFormatInternal(locale, style, errorCode);
- if (U_FAILURE(errorCode)) {
- return nullptr;
- }
- ListFormatter* p = new ListFormatter(listFormatInternal);
- if (p == nullptr) {
- errorCode = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
- return p;
-}
-
-ListFormatter::ListFormatter(const ListFormatData& listFormatData, UErrorCode &errorCode) {
- owned = new ListFormatInternal(listFormatData, errorCode);
- data = owned;
-}
-
-ListFormatter::ListFormatter(const ListFormatInternal* listFormatterInternal) : owned(nullptr), data(listFormatterInternal) {
-}
-
-ListFormatter::~ListFormatter() {
- delete owned;
-}
-
-/**
- * Joins first and second using the pattern pat.
- * On entry offset is an offset into first or -1 if offset unspecified.
- * On exit offset is offset of second in result if recordOffset was set
- * Otherwise if it was >=0 it is set to point into result where it used
- * to point into first. On exit, result is the join of first and second
- * according to pat. Any previous value of result gets replaced.
- */
-static void joinStringsAndReplace(
- const SimpleFormatter& pat,
- const UnicodeString& first,
- const UnicodeString& second,
- UnicodeString &result,
- UBool recordOffset,
- int32_t &offset,
- int32_t *offsetFirst,
- int32_t *offsetSecond,
- UErrorCode& errorCode) {
- if (U_FAILURE(errorCode)) {
- return;
- }
- const UnicodeString *params[2] = {&first, &second};
- int32_t offsets[2];
- pat.formatAndReplace(
- params,
- UPRV_LENGTHOF(params),
- result,
- offsets,
- UPRV_LENGTHOF(offsets),
- errorCode);
- if (U_FAILURE(errorCode)) {
- return;
- }
- if (offsets[0] == -1 || offsets[1] == -1) {
- errorCode = U_INVALID_FORMAT_ERROR;
- return;
- }
- if (recordOffset) {
- offset = offsets[1];
- } else if (offset >= 0) {
- offset += offsets[0];
- }
- if (offsetFirst != nullptr) *offsetFirst = offsets[0];
- if (offsetSecond != nullptr) *offsetSecond = offsets[1];
-}
-
-UnicodeString& ListFormatter::format(
- const UnicodeString items[],
- int32_t nItems,
- UnicodeString& appendTo,
- UErrorCode& errorCode) const {
- int32_t offset;
- return format(items, nItems, appendTo, -1, offset, errorCode);
-}
-
-UnicodeString& ListFormatter::format(
- const UnicodeString items[],
- int32_t nItems,
- UnicodeString& appendTo,
- int32_t index,
- int32_t &offset,
- UErrorCode& errorCode) const {
- return format_(items, nItems, appendTo, index, offset, nullptr, errorCode);
-}
-
-#if !UCONFIG_NO_FORMATTING
-FormattedList ListFormatter::formatStringsToValue(
- const UnicodeString items[],
- int32_t nItems,
- UErrorCode& errorCode) const {
- LocalPointer<FormattedListData> result(new FormattedListData(errorCode), errorCode);
- if (U_FAILURE(errorCode)) {
- return FormattedList(errorCode);
- }
- UnicodeString string;
- int32_t offset;
- auto handler = result->getHandler(errorCode);
- handler.setCategory(UFIELD_CATEGORY_LIST);
- format_(items, nItems, string, -1, offset, &handler, errorCode);
- handler.getError(errorCode);
- result->appendString(string, errorCode);
- if (U_FAILURE(errorCode)) {
- return FormattedList(errorCode);
- }
-
- // Add span fields and sort
- ConstrainedFieldPosition cfpos;
- cfpos.constrainField(UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD);
- int32_t i = 0;
- handler.setCategory(UFIELD_CATEGORY_LIST_SPAN);
- while (result->nextPosition(cfpos, errorCode)) {
- handler.addAttribute(i++, cfpos.getStart(), cfpos.getLimit());
- }
- handler.getError(errorCode);
- if (U_FAILURE(errorCode)) {
- return FormattedList(errorCode);
- }
- result->sort();
-
- return FormattedList(result.orphan());
-}
-#endif
-
-UnicodeString& ListFormatter::format_(
- const UnicodeString items[],
- int32_t nItems,
- UnicodeString& appendTo,
- int32_t index,
- int32_t &offset,
- FieldPositionHandler* handler,
- UErrorCode& errorCode) const {
-#if !UCONFIG_NO_FORMATTING
- offset = -1;
- if (U_FAILURE(errorCode)) {
- return appendTo;
- }
- if (data == nullptr) {
- errorCode = U_INVALID_STATE_ERROR;
- return appendTo;
- }
-
- if (nItems <= 0) {
- return appendTo;
- }
- if (nItems == 1) {
- if (index == 0) {
- offset = appendTo.length();
- }
- if (handler != nullptr) {
- handler->addAttribute(ULISTFMT_ELEMENT_FIELD,
- appendTo.length(),
- appendTo.length() + items[0].length());
- }
- appendTo.append(items[0]);
- return appendTo;
- }
- UnicodeString result(items[0]);
- if (index == 0) {
- offset = 0;
- }
- int32_t offsetFirst = 0;
- int32_t offsetSecond = 0;
- int32_t prefixLength = 0;
- // for n items, there are 2 * (n + 1) boundary including 0 and the upper
- // edge.
- MaybeStackArray<int32_t, 10> offsets((handler != nullptr) ? 2 * (nItems + 1): 0);
- if (nItems == 2) {
- joinStringsAndReplace(
- data->patternHandler->getTwoPattern(items[1]),
- result,
- items[1],
- result,
- index == 1,
- offset,
- &offsetFirst,
- &offsetSecond,
- errorCode);
- } else {
- joinStringsAndReplace(
- data->startPattern,
- result,
- items[1],
- result,
- index == 1,
- offset,
- &offsetFirst,
- &offsetSecond,
- errorCode);
- }
- if (handler != nullptr) {
- offsets[0] = 0;
- prefixLength += offsetFirst;
- offsets[1] = offsetSecond - prefixLength;
- }
- if (nItems > 2) {
- for (int32_t i = 2; i < nItems - 1; ++i) {
- joinStringsAndReplace(
- data->middlePattern,
- result,
- items[i],
- result,
- index == i,
- offset,
- &offsetFirst,
- &offsetSecond,
- errorCode);
- if (handler != nullptr) {
- prefixLength += offsetFirst;
- offsets[i] = offsetSecond - prefixLength;
- }
- }
- joinStringsAndReplace(
- data->patternHandler->getEndPattern(items[nItems - 1]),
- result,
- items[nItems - 1],
- result,
- index == nItems - 1,
- offset,
- &offsetFirst,
- &offsetSecond,
- errorCode);
- if (handler != nullptr) {
- prefixLength += offsetFirst;
- offsets[nItems - 1] = offsetSecond - prefixLength;
- }
- }
- if (handler != nullptr) {
- // If there are already some data in appendTo, we need to adjust the index
- // by shifting that lenght while insert into handler.
- int32_t shift = appendTo.length() + prefixLength;
- // Output the ULISTFMT_ELEMENT_FIELD in the order of the input elements
- for (int32_t i = 0; i < nItems; ++i) {
- offsets[i + nItems] = offsets[i] + items[i].length() + shift;
- offsets[i] += shift;
- handler->addAttribute(
- ULISTFMT_ELEMENT_FIELD, // id
- offsets[i], // index
- offsets[i + nItems]); // limit
- }
- // The locale pattern may reorder the items (such as in ur-IN locale),
- // so we cannot assume the array is in accendning order.
- // To handle the edging case, just insert the two ends into the array
- // and sort. Then we output ULISTFMT_LITERAL_FIELD if the indecies
- // between the even and odd position are not the same in the sorted array.
- offsets[2 * nItems] = shift - prefixLength;
- offsets[2 * nItems + 1] = result.length() + shift - prefixLength;
- uprv_sortArray(offsets.getAlias(), 2 * (nItems + 1), sizeof(int32_t),
- uprv_int32Comparator, nullptr,
- false, &errorCode);
- for (int32_t i = 0; i <= nItems; ++i) {
- if (offsets[i * 2] != offsets[i * 2 + 1]) {
- handler->addAttribute(
- ULISTFMT_LITERAL_FIELD, // id
- offsets[i * 2], // index
- offsets[i * 2 + 1]); // limit
- }
- }
- }
- if (U_SUCCESS(errorCode)) {
- if (offset >= 0) {
- offset += appendTo.length();
- }
- appendTo += result;
- }
-#endif
- return appendTo;
-}
-
-U_NAMESPACE_END
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+*******************************************************************************
+*
+* Copyright (C) 2013-2016, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+*******************************************************************************
+* file name: listformatter.cpp
+* encoding: UTF-8
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2012aug27
+* created by: Umesh P. Nair
+*/
+
+#include "cmemory.h"
+#include "unicode/fpositer.h" // FieldPositionIterator
+#include "unicode/listformatter.h"
+#include "unicode/simpleformatter.h"
+#include "unicode/ulistformatter.h"
+#include "unicode/uscript.h"
+#include "fphdlimp.h"
+#include "mutex.h"
+#include "hash.h"
+#include "cstring.h"
+#include "uarrsort.h"
+#include "ulocimp.h"
+#include "charstr.h"
+#include "ucln_in.h"
+#include "uresimp.h"
+#include "resource.h"
+#include "formattedval_impl.h"
+
+U_NAMESPACE_BEGIN
+
+namespace {
+
+class PatternHandler : public UObject {
+public:
+ PatternHandler(const UnicodeString& two, const UnicodeString& end, UErrorCode& errorCode) :
+ twoPattern(two, 2, 2, errorCode),
+ endPattern(end, 2, 2, errorCode) { }
+
+ PatternHandler(const SimpleFormatter& two, const SimpleFormatter& end) :
+ twoPattern(two),
+ endPattern(end) { }
+
+ virtual ~PatternHandler();
+
+ virtual PatternHandler* clone() const { return new PatternHandler(twoPattern, endPattern); }
+
+ virtual const SimpleFormatter& getTwoPattern(const UnicodeString&) const {
+ return twoPattern;
+ }
+
+ virtual const SimpleFormatter& getEndPattern(const UnicodeString&) const {
+ return endPattern;
+ }
+
+protected:
+ SimpleFormatter twoPattern;
+ SimpleFormatter endPattern;
+};
+
+PatternHandler::~PatternHandler() {
+}
+
+class ContextualHandler : public PatternHandler {
+public:
+ ContextualHandler(bool (*testFunc)(const UnicodeString& text),
+ const UnicodeString& thenTwo,
+ const UnicodeString& elseTwo,
+ const UnicodeString& thenEnd,
+ const UnicodeString& elseEnd,
+ UErrorCode& errorCode) :
+ PatternHandler(elseTwo, elseEnd, errorCode),
+ test(testFunc),
+ thenTwoPattern(thenTwo, 2, 2, errorCode),
+ thenEndPattern(thenEnd, 2, 2, errorCode) { }
+
+ ContextualHandler(bool (*testFunc)(const UnicodeString& text),
+ const SimpleFormatter& thenTwo, SimpleFormatter elseTwo,
+ const SimpleFormatter& thenEnd, SimpleFormatter elseEnd) :
+ PatternHandler(elseTwo, elseEnd),
+ test(testFunc),
+ thenTwoPattern(thenTwo),
+ thenEndPattern(thenEnd) { }
+
+ ~ContextualHandler() override;
+
+ PatternHandler* clone() const override {
+ return new ContextualHandler(
+ test, thenTwoPattern, twoPattern, thenEndPattern, endPattern);
+ }
+
+ const SimpleFormatter& getTwoPattern(
+ const UnicodeString& text) const override {
+ return (test)(text) ? thenTwoPattern : twoPattern;
+ }
+
+ const SimpleFormatter& getEndPattern(
+ const UnicodeString& text) const override {
+ return (test)(text) ? thenEndPattern : endPattern;
+ }
+
+private:
+ bool (*test)(const UnicodeString&);
+ SimpleFormatter thenTwoPattern;
+ SimpleFormatter thenEndPattern;
+};
+
+ContextualHandler::~ContextualHandler() {
+}
+
+static const char16_t *spanishY = u"{0} y {1}";
+static const char16_t *spanishE = u"{0} e {1}";
+static const char16_t *spanishO = u"{0} o {1}";
+static const char16_t *spanishU = u"{0} u {1}";
+static const char16_t *hebrewVav = u"{0} \u05D5{1}";
+static const char16_t *hebrewVavDash = u"{0} \u05D5-{1}";
+
+// Condiction to change to e.
+// Starts with "hi" or "i" but not with "hie" nor "hia"
+static bool shouldChangeToE(const UnicodeString& text) {
+ int32_t len = text.length();
+ if (len == 0) { return false; }
+ // Case insensitive match hi but not hie nor hia.
+ if ((text[0] == u'h' || text[0] == u'H') &&
+ ((len > 1) && (text[1] == u'i' || text[1] == u'I')) &&
+ ((len == 2) || !(text[2] == u'a' || text[2] == u'A' || text[2] == u'e' || text[2] == u'E'))) {
+ return true;
+ }
+ // Case insensitive for "start with i"
+ if (text[0] == u'i' || text[0] == u'I') { return true; }
+ return false;
+}
+
+// Condiction to change to u.
+// Starts with "o", "ho", and "8". Also "11" by itself.
+// re: ^((o|ho|8).*|11)$
+static bool shouldChangeToU(const UnicodeString& text) {
+ int32_t len = text.length();
+ if (len == 0) { return false; }
+ // Case insensitive match o.* and 8.*
+ if (text[0] == u'o' || text[0] == u'O' || text[0] == u'8') { return true; }
+ // Case insensitive match ho.*
+ if ((text[0] == u'h' || text[0] == u'H') &&
+ ((len > 1) && (text[1] == 'o' || text[1] == u'O'))) {
+ return true;
+ }
+ // match "^11$" and "^11 .*"
+ if ((len >= 2) && text[0] == u'1' && text[1] == u'1' && (len == 2 || text[2] == u' ')) { return true; }
+ return false;
+}
+
+// Condiction to change to VAV follow by a dash.
+// Starts with non Hebrew letter.
+static bool shouldChangeToVavDash(const UnicodeString& text) {
+ if (text.isEmpty()) { return false; }
+ UErrorCode status = U_ZERO_ERROR;
+ return uscript_getScript(text.char32At(0), &status) != USCRIPT_HEBREW;
+}
+
+PatternHandler* createPatternHandler(
+ const char* lang, const UnicodeString& two, const UnicodeString& end,
+ UErrorCode& status) {
+ if (uprv_strcmp(lang, "es") == 0) {
+ // Spanish
+ UnicodeString spanishYStr(TRUE, spanishY, -1);
+ bool twoIsY = two == spanishYStr;
+ bool endIsY = end == spanishYStr;
+ if (twoIsY || endIsY) {
+ UnicodeString replacement(TRUE, spanishE, -1);
+ return new ContextualHandler(
+ shouldChangeToE,
+ twoIsY ? replacement : two, two,
+ endIsY ? replacement : end, end, status);
+ }
+ UnicodeString spanishOStr(TRUE, spanishO, -1);
+ bool twoIsO = two == spanishOStr;
+ bool endIsO = end == spanishOStr;
+ if (twoIsO || endIsO) {
+ UnicodeString replacement(TRUE, spanishU, -1);
+ return new ContextualHandler(
+ shouldChangeToU,
+ twoIsO ? replacement : two, two,
+ endIsO ? replacement : end, end, status);
+ }
+ } else if (uprv_strcmp(lang, "he") == 0 || uprv_strcmp(lang, "iw") == 0) {
+ // Hebrew
+ UnicodeString hebrewVavStr(TRUE, hebrewVav, -1);
+ bool twoIsVav = two == hebrewVavStr;
+ bool endIsVav = end == hebrewVavStr;
+ if (twoIsVav || endIsVav) {
+ UnicodeString replacement(TRUE, hebrewVavDash, -1);
+ return new ContextualHandler(
+ shouldChangeToVavDash,
+ twoIsVav ? replacement : two, two,
+ endIsVav ? replacement : end, end, status);
+ }
+ }
+ return new PatternHandler(two, end, status);
+}
+
+} // namespace
+
+struct ListFormatInternal : public UMemory {
+ SimpleFormatter startPattern;
+ SimpleFormatter middlePattern;
+ LocalPointer<PatternHandler> patternHandler;
+
+ListFormatInternal(
+ const UnicodeString& two,
+ const UnicodeString& start,
+ const UnicodeString& middle,
+ const UnicodeString& end,
+ const Locale& locale,
+ UErrorCode &errorCode) :
+ startPattern(start, 2, 2, errorCode),
+ middlePattern(middle, 2, 2, errorCode),
+ patternHandler(createPatternHandler(locale.getLanguage(), two, end, errorCode), errorCode) { }
+
+ListFormatInternal(const ListFormatData &data, UErrorCode &errorCode) :
+ startPattern(data.startPattern, errorCode),
+ middlePattern(data.middlePattern, errorCode),
+ patternHandler(createPatternHandler(
+ data.locale.getLanguage(), data.twoPattern, data.endPattern, errorCode), errorCode) { }
+
+ListFormatInternal(const ListFormatInternal &other) :
+ startPattern(other.startPattern),
+ middlePattern(other.middlePattern),
+ patternHandler(other.patternHandler->clone()) { }
+};
+
+
+#if !UCONFIG_NO_FORMATTING
+class FormattedListData : public FormattedValueFieldPositionIteratorImpl {
+public:
+ FormattedListData(UErrorCode& status) : FormattedValueFieldPositionIteratorImpl(5, status) {}
+ virtual ~FormattedListData();
+};
+
+FormattedListData::~FormattedListData() = default;
+
+UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(FormattedList)
+#endif
+
+
+static Hashtable* listPatternHash = nullptr;
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV uprv_listformatter_cleanup() {
+ delete listPatternHash;
+ listPatternHash = nullptr;
+ return TRUE;
+}
+
+static void U_CALLCONV
+uprv_deleteListFormatInternal(void *obj) {
+ delete static_cast<ListFormatInternal *>(obj);
+}
+
+U_CDECL_END
+
+ListFormatter::ListFormatter(const ListFormatter& other) :
+ owned(other.owned), data(other.data) {
+ if (other.owned != nullptr) {
+ owned = new ListFormatInternal(*other.owned);
+ data = owned;
+ }
+}
+
+ListFormatter& ListFormatter::operator=(const ListFormatter& other) {
+ if (this == &other) {
+ return *this;
+ }
+ delete owned;
+ if (other.owned) {
+ owned = new ListFormatInternal(*other.owned);
+ data = owned;
+ } else {
+ owned = nullptr;
+ data = other.data;
+ }
+ return *this;
+}
+
+void ListFormatter::initializeHash(UErrorCode& errorCode) {
+ if (U_FAILURE(errorCode)) {
+ return;
+ }
+
+ listPatternHash = new Hashtable();
+ if (listPatternHash == nullptr) {
+ errorCode = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ listPatternHash->setValueDeleter(uprv_deleteListFormatInternal);
+ ucln_i18n_registerCleanup(UCLN_I18N_LIST_FORMATTER, uprv_listformatter_cleanup);
+
+}
+
+const ListFormatInternal* ListFormatter::getListFormatInternal(
+ const Locale& locale, const char *style, UErrorCode& errorCode) {
+ if (U_FAILURE(errorCode)) {
+ return nullptr;
+ }
+ CharString keyBuffer(locale.getName(), errorCode);
+ keyBuffer.append(':', errorCode).append(style, errorCode);
+ UnicodeString key(keyBuffer.data(), -1, US_INV);
+ ListFormatInternal* result = nullptr;
+ static UMutex listFormatterMutex;
+ {
+ Mutex m(&listFormatterMutex);
+ if (listPatternHash == nullptr) {
+ initializeHash(errorCode);
+ if (U_FAILURE(errorCode)) {
+ return nullptr;
+ }
+ }
+ result = static_cast<ListFormatInternal*>(listPatternHash->get(key));
+ }
+ if (result != nullptr) {
+ return result;
+ }
+ result = loadListFormatInternal(locale, style, errorCode);
+ if (U_FAILURE(errorCode)) {
+ return nullptr;
+ }
+
+ {
+ Mutex m(&listFormatterMutex);
+ ListFormatInternal* temp = static_cast<ListFormatInternal*>(listPatternHash->get(key));
+ if (temp != nullptr) {
+ delete result;
+ result = temp;
+ } else {
+ listPatternHash->put(key, result, errorCode);
+ if (U_FAILURE(errorCode)) {
+ return nullptr;
+ }
+ }
+ }
+ return result;
+}
+
+#if !UCONFIG_NO_FORMATTING
+static const char* typeWidthToStyleString(UListFormatterType type, UListFormatterWidth width) {
+ switch (type) {
+ case ULISTFMT_TYPE_AND:
+ switch (width) {
+ case ULISTFMT_WIDTH_WIDE:
+ return "standard";
+ case ULISTFMT_WIDTH_SHORT:
+ return "standard-short";
+ case ULISTFMT_WIDTH_NARROW:
+ return "standard-narrow";
+ default:
+ return nullptr;
+ }
+ break;
+
+ case ULISTFMT_TYPE_OR:
+ switch (width) {
+ case ULISTFMT_WIDTH_WIDE:
+ return "or";
+ case ULISTFMT_WIDTH_SHORT:
+ return "or-short";
+ case ULISTFMT_WIDTH_NARROW:
+ return "or-narrow";
+ default:
+ return nullptr;
+ }
+ break;
+
+ case ULISTFMT_TYPE_UNITS:
+ switch (width) {
+ case ULISTFMT_WIDTH_WIDE:
+ return "unit";
+ case ULISTFMT_WIDTH_SHORT:
+ return "unit-short";
+ case ULISTFMT_WIDTH_NARROW:
+ return "unit-narrow";
+ default:
+ return nullptr;
+ }
+ }
+
+ return nullptr;
+}
+#endif
+
+static const UChar solidus = 0x2F;
+static const UChar aliasPrefix[] = { 0x6C,0x69,0x73,0x74,0x50,0x61,0x74,0x74,0x65,0x72,0x6E,0x2F }; // "listPattern/"
+enum {
+ kAliasPrefixLen = UPRV_LENGTHOF(aliasPrefix),
+ kStyleLenMax = 24 // longest currently is 14
+};
+
+struct ListFormatter::ListPatternsSink : public ResourceSink {
+ UnicodeString two, start, middle, end;
+#if ((U_PLATFORM == U_PF_AIX) || (U_PLATFORM == U_PF_OS390)) && (U_CPLUSPLUS_VERSION < 11)
+ char aliasedStyle[kStyleLenMax+1];
+ ListPatternsSink() {
+ uprv_memset(aliasedStyle, 0, kStyleLenMax+1);
+ }
+#else
+ char aliasedStyle[kStyleLenMax+1] = {0};
+
+ ListPatternsSink() {}
+#endif
+ virtual ~ListPatternsSink();
+
+ void setAliasedStyle(UnicodeString alias) {
+ int32_t startIndex = alias.indexOf(aliasPrefix, kAliasPrefixLen, 0);
+ if (startIndex < 0) {
+ return;
+ }
+ startIndex += kAliasPrefixLen;
+ int32_t endIndex = alias.indexOf(solidus, startIndex);
+ if (endIndex < 0) {
+ endIndex = alias.length();
+ }
+ alias.extract(startIndex, endIndex-startIndex, aliasedStyle, kStyleLenMax+1, US_INV);
+ aliasedStyle[kStyleLenMax] = 0;
+ }
+
+ void handleValueForPattern(ResourceValue &value, UnicodeString &pattern, UErrorCode &errorCode) {
+ if (pattern.isEmpty()) {
+ if (value.getType() == URES_ALIAS) {
+ if (aliasedStyle[0] == 0) {
+ setAliasedStyle(value.getAliasUnicodeString(errorCode));
+ }
+ } else {
+ pattern = value.getUnicodeString(errorCode);
+ }
+ }
+ }
+
+ virtual void put(const char *key, ResourceValue &value, UBool /*noFallback*/,
+ UErrorCode &errorCode) {
+ aliasedStyle[0] = 0;
+ if (value.getType() == URES_ALIAS) {
+ setAliasedStyle(value.getAliasUnicodeString(errorCode));
+ return;
+ }
+ ResourceTable listPatterns = value.getTable(errorCode);
+ for (int i = 0; U_SUCCESS(errorCode) && listPatterns.getKeyAndValue(i, key, value); ++i) {
+ if (uprv_strcmp(key, "2") == 0) {
+ handleValueForPattern(value, two, errorCode);
+ } else if (uprv_strcmp(key, "end") == 0) {
+ handleValueForPattern(value, end, errorCode);
+ } else if (uprv_strcmp(key, "middle") == 0) {
+ handleValueForPattern(value, middle, errorCode);
+ } else if (uprv_strcmp(key, "start") == 0) {
+ handleValueForPattern(value, start, errorCode);
+ }
+ }
+ }
+};
+
+// Virtual destructors must be defined out of line.
+ListFormatter::ListPatternsSink::~ListPatternsSink() {}
+
+ListFormatInternal* ListFormatter::loadListFormatInternal(
+ const Locale& locale, const char * style, UErrorCode& errorCode) {
+ UResourceBundle* rb = ures_open(nullptr, locale.getName(), &errorCode);
+ rb = ures_getByKeyWithFallback(rb, "listPattern", rb, &errorCode);
+ if (U_FAILURE(errorCode)) {
+ ures_close(rb);
+ return nullptr;
+ }
+ ListFormatter::ListPatternsSink sink;
+ char currentStyle[kStyleLenMax+1];
+ uprv_strncpy(currentStyle, style, kStyleLenMax);
+ currentStyle[kStyleLenMax] = 0;
+
+ for (;;) {
+ ures_getAllItemsWithFallback(rb, currentStyle, sink, errorCode);
+ if (U_FAILURE(errorCode) || sink.aliasedStyle[0] == 0 || uprv_strcmp(currentStyle, sink.aliasedStyle) == 0) {
+ break;
+ }
+ uprv_strcpy(currentStyle, sink.aliasedStyle);
+ }
+ ures_close(rb);
+ if (U_FAILURE(errorCode)) {
+ return nullptr;
+ }
+ if (sink.two.isEmpty() || sink.start.isEmpty() || sink.middle.isEmpty() || sink.end.isEmpty()) {
+ errorCode = U_MISSING_RESOURCE_ERROR;
+ return nullptr;
+ }
+
+ ListFormatInternal* result = new ListFormatInternal(sink.two, sink.start, sink.middle, sink.end, locale, errorCode);
+ if (result == nullptr) {
+ errorCode = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+ if (U_FAILURE(errorCode)) {
+ delete result;
+ return nullptr;
+ }
+ return result;
+}
+
+ListFormatter* ListFormatter::createInstance(UErrorCode& errorCode) {
+ Locale locale; // The default locale.
+ return createInstance(locale, errorCode);
+}
+
+ListFormatter* ListFormatter::createInstance(const Locale& locale, UErrorCode& errorCode) {
+#if !UCONFIG_NO_FORMATTING
+ return createInstance(locale, ULISTFMT_TYPE_AND, ULISTFMT_WIDTH_WIDE, errorCode);
+#else
+ return createInstance(locale, "standard", errorCode);
+#endif
+}
+
+#if !UCONFIG_NO_FORMATTING
+ListFormatter* ListFormatter::createInstance(
+ const Locale& locale, UListFormatterType type, UListFormatterWidth width, UErrorCode& errorCode) {
+ const char* style = typeWidthToStyleString(type, width);
+ if (style == nullptr) {
+ errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return nullptr;
+ }
+ return createInstance(locale, style, errorCode);
+}
+#endif
+
+ListFormatter* ListFormatter::createInstance(const Locale& locale, const char *style, UErrorCode& errorCode) {
+ const ListFormatInternal* listFormatInternal = getListFormatInternal(locale, style, errorCode);
+ if (U_FAILURE(errorCode)) {
+ return nullptr;
+ }
+ ListFormatter* p = new ListFormatter(listFormatInternal);
+ if (p == nullptr) {
+ errorCode = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+ return p;
+}
+
+ListFormatter::ListFormatter(const ListFormatData& listFormatData, UErrorCode &errorCode) {
+ owned = new ListFormatInternal(listFormatData, errorCode);
+ data = owned;
+}
+
+ListFormatter::ListFormatter(const ListFormatInternal* listFormatterInternal) : owned(nullptr), data(listFormatterInternal) {
+}
+
+ListFormatter::~ListFormatter() {
+ delete owned;
+}
+
+/**
+ * Joins first and second using the pattern pat.
+ * On entry offset is an offset into first or -1 if offset unspecified.
+ * On exit offset is offset of second in result if recordOffset was set
+ * Otherwise if it was >=0 it is set to point into result where it used
+ * to point into first. On exit, result is the join of first and second
+ * according to pat. Any previous value of result gets replaced.
+ */
+static void joinStringsAndReplace(
+ const SimpleFormatter& pat,
+ const UnicodeString& first,
+ const UnicodeString& second,
+ UnicodeString &result,
+ UBool recordOffset,
+ int32_t &offset,
+ int32_t *offsetFirst,
+ int32_t *offsetSecond,
+ UErrorCode& errorCode) {
+ if (U_FAILURE(errorCode)) {
+ return;
+ }
+ const UnicodeString *params[2] = {&first, &second};
+ int32_t offsets[2];
+ pat.formatAndReplace(
+ params,
+ UPRV_LENGTHOF(params),
+ result,
+ offsets,
+ UPRV_LENGTHOF(offsets),
+ errorCode);
+ if (U_FAILURE(errorCode)) {
+ return;
+ }
+ if (offsets[0] == -1 || offsets[1] == -1) {
+ errorCode = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+ if (recordOffset) {
+ offset = offsets[1];
+ } else if (offset >= 0) {
+ offset += offsets[0];
+ }
+ if (offsetFirst != nullptr) *offsetFirst = offsets[0];
+ if (offsetSecond != nullptr) *offsetSecond = offsets[1];
+}
+
+UnicodeString& ListFormatter::format(
+ const UnicodeString items[],
+ int32_t nItems,
+ UnicodeString& appendTo,
+ UErrorCode& errorCode) const {
+ int32_t offset;
+ return format(items, nItems, appendTo, -1, offset, errorCode);
+}
+
+UnicodeString& ListFormatter::format(
+ const UnicodeString items[],
+ int32_t nItems,
+ UnicodeString& appendTo,
+ int32_t index,
+ int32_t &offset,
+ UErrorCode& errorCode) const {
+ return format_(items, nItems, appendTo, index, offset, nullptr, errorCode);
+}
+
+#if !UCONFIG_NO_FORMATTING
+FormattedList ListFormatter::formatStringsToValue(
+ const UnicodeString items[],
+ int32_t nItems,
+ UErrorCode& errorCode) const {
+ LocalPointer<FormattedListData> result(new FormattedListData(errorCode), errorCode);
+ if (U_FAILURE(errorCode)) {
+ return FormattedList(errorCode);
+ }
+ UnicodeString string;
+ int32_t offset;
+ auto handler = result->getHandler(errorCode);
+ handler.setCategory(UFIELD_CATEGORY_LIST);
+ format_(items, nItems, string, -1, offset, &handler, errorCode);
+ handler.getError(errorCode);
+ result->appendString(string, errorCode);
+ if (U_FAILURE(errorCode)) {
+ return FormattedList(errorCode);
+ }
+
+ // Add span fields and sort
+ ConstrainedFieldPosition cfpos;
+ cfpos.constrainField(UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD);
+ int32_t i = 0;
+ handler.setCategory(UFIELD_CATEGORY_LIST_SPAN);
+ while (result->nextPosition(cfpos, errorCode)) {
+ handler.addAttribute(i++, cfpos.getStart(), cfpos.getLimit());
+ }
+ handler.getError(errorCode);
+ if (U_FAILURE(errorCode)) {
+ return FormattedList(errorCode);
+ }
+ result->sort();
+
+ return FormattedList(result.orphan());
+}
+#endif
+
+UnicodeString& ListFormatter::format_(
+ const UnicodeString items[],
+ int32_t nItems,
+ UnicodeString& appendTo,
+ int32_t index,
+ int32_t &offset,
+ FieldPositionHandler* handler,
+ UErrorCode& errorCode) const {
+#if !UCONFIG_NO_FORMATTING
+ offset = -1;
+ if (U_FAILURE(errorCode)) {
+ return appendTo;
+ }
+ if (data == nullptr) {
+ errorCode = U_INVALID_STATE_ERROR;
+ return appendTo;
+ }
+
+ if (nItems <= 0) {
+ return appendTo;
+ }
+ if (nItems == 1) {
+ if (index == 0) {
+ offset = appendTo.length();
+ }
+ if (handler != nullptr) {
+ handler->addAttribute(ULISTFMT_ELEMENT_FIELD,
+ appendTo.length(),
+ appendTo.length() + items[0].length());
+ }
+ appendTo.append(items[0]);
+ return appendTo;
+ }
+ UnicodeString result(items[0]);
+ if (index == 0) {
+ offset = 0;
+ }
+ int32_t offsetFirst = 0;
+ int32_t offsetSecond = 0;
+ int32_t prefixLength = 0;
+ // for n items, there are 2 * (n + 1) boundary including 0 and the upper
+ // edge.
+ MaybeStackArray<int32_t, 10> offsets((handler != nullptr) ? 2 * (nItems + 1): 0);
+ if (nItems == 2) {
+ joinStringsAndReplace(
+ data->patternHandler->getTwoPattern(items[1]),
+ result,
+ items[1],
+ result,
+ index == 1,
+ offset,
+ &offsetFirst,
+ &offsetSecond,
+ errorCode);
+ } else {
+ joinStringsAndReplace(
+ data->startPattern,
+ result,
+ items[1],
+ result,
+ index == 1,
+ offset,
+ &offsetFirst,
+ &offsetSecond,
+ errorCode);
+ }
+ if (handler != nullptr) {
+ offsets[0] = 0;
+ prefixLength += offsetFirst;
+ offsets[1] = offsetSecond - prefixLength;
+ }
+ if (nItems > 2) {
+ for (int32_t i = 2; i < nItems - 1; ++i) {
+ joinStringsAndReplace(
+ data->middlePattern,
+ result,
+ items[i],
+ result,
+ index == i,
+ offset,
+ &offsetFirst,
+ &offsetSecond,
+ errorCode);
+ if (handler != nullptr) {
+ prefixLength += offsetFirst;
+ offsets[i] = offsetSecond - prefixLength;
+ }
+ }
+ joinStringsAndReplace(
+ data->patternHandler->getEndPattern(items[nItems - 1]),
+ result,
+ items[nItems - 1],
+ result,
+ index == nItems - 1,
+ offset,
+ &offsetFirst,
+ &offsetSecond,
+ errorCode);
+ if (handler != nullptr) {
+ prefixLength += offsetFirst;
+ offsets[nItems - 1] = offsetSecond - prefixLength;
+ }
+ }
+ if (handler != nullptr) {
+ // If there are already some data in appendTo, we need to adjust the index
+ // by shifting that lenght while insert into handler.
+ int32_t shift = appendTo.length() + prefixLength;
+ // Output the ULISTFMT_ELEMENT_FIELD in the order of the input elements
+ for (int32_t i = 0; i < nItems; ++i) {
+ offsets[i + nItems] = offsets[i] + items[i].length() + shift;
+ offsets[i] += shift;
+ handler->addAttribute(
+ ULISTFMT_ELEMENT_FIELD, // id
+ offsets[i], // index
+ offsets[i + nItems]); // limit
+ }
+ // The locale pattern may reorder the items (such as in ur-IN locale),
+ // so we cannot assume the array is in accendning order.
+ // To handle the edging case, just insert the two ends into the array
+ // and sort. Then we output ULISTFMT_LITERAL_FIELD if the indecies
+ // between the even and odd position are not the same in the sorted array.
+ offsets[2 * nItems] = shift - prefixLength;
+ offsets[2 * nItems + 1] = result.length() + shift - prefixLength;
+ uprv_sortArray(offsets.getAlias(), 2 * (nItems + 1), sizeof(int32_t),
+ uprv_int32Comparator, nullptr,
+ false, &errorCode);
+ for (int32_t i = 0; i <= nItems; ++i) {
+ if (offsets[i * 2] != offsets[i * 2 + 1]) {
+ handler->addAttribute(
+ ULISTFMT_LITERAL_FIELD, // id
+ offsets[i * 2], // index
+ offsets[i * 2 + 1]); // limit
+ }
+ }
+ }
+ if (U_SUCCESS(errorCode)) {
+ if (offset >= 0) {
+ offset += appendTo.length();
+ }
+ appendTo += result;
+ }
+#endif
+ return appendTo;
+}
+
+U_NAMESPACE_END
diff --git a/contrib/libs/icu/i18n/measfmt.cpp b/contrib/libs/icu/i18n/measfmt.cpp
index e05d66d413..92dcfb9cf3 100644
--- a/contrib/libs/icu/i18n/measfmt.cpp
+++ b/contrib/libs/icu/i18n/measfmt.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -26,7 +26,7 @@
#include "unicode/decimfmt.h"
#include "uresimp.h"
#include "unicode/ures.h"
-#include "unicode/ustring.h"
+#include "unicode/ustring.h"
#include "ureslocs.h"
#include "cstring.h"
#include "mutex.h"
@@ -36,9 +36,9 @@
#include "unicode/putil.h"
#include "unicode/smpdtfmt.h"
#include "uassert.h"
-#include "unicode/numberformatter.h"
-#include "number_longnames.h"
-#include "number_utypes.h"
+#include "unicode/numberformatter.h"
+#include "number_longnames.h"
+#include "number_utypes.h"
#include "sharednumberformat.h"
#include "sharedpluralrules.h"
@@ -48,33 +48,33 @@
U_NAMESPACE_BEGIN
-using number::impl::UFormattedNumberData;
-
-static constexpr int32_t WIDTH_INDEX_COUNT = UMEASFMT_WIDTH_NARROW + 1;
-
+using number::impl::UFormattedNumberData;
+
+static constexpr int32_t WIDTH_INDEX_COUNT = UMEASFMT_WIDTH_NARROW + 1;
+
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MeasureFormat)
// Used to format durations like 5:47 or 21:35:42.
class NumericDateFormatters : public UMemory {
public:
// Formats like H:mm
- UnicodeString hourMinute;
+ UnicodeString hourMinute;
// formats like M:ss
- UnicodeString minuteSecond;
+ UnicodeString minuteSecond;
// formats like H:mm:ss
- UnicodeString hourMinuteSecond;
+ UnicodeString hourMinuteSecond;
// Constructor that takes the actual patterns for hour-minute,
// minute-second, and hour-minute-second respectively.
NumericDateFormatters(
const UnicodeString &hm,
const UnicodeString &ms,
- const UnicodeString &hms) :
- hourMinute(hm),
- minuteSecond(ms),
- hourMinuteSecond(hms) {
+ const UnicodeString &hms) :
+ hourMinute(hm),
+ minuteSecond(ms),
+ hourMinuteSecond(hms) {
}
private:
NumericDateFormatters(const NumericDateFormatters &other);
@@ -88,19 +88,19 @@ static UMeasureFormatWidth getRegularWidth(UMeasureFormatWidth width) {
return width;
}
-static UNumberUnitWidth getUnitWidth(UMeasureFormatWidth width) {
- switch (width) {
- case UMEASFMT_WIDTH_WIDE:
- return UNUM_UNIT_WIDTH_FULL_NAME;
- case UMEASFMT_WIDTH_NARROW:
- case UMEASFMT_WIDTH_NUMERIC:
- return UNUM_UNIT_WIDTH_NARROW;
- case UMEASFMT_WIDTH_SHORT:
- default:
- return UNUM_UNIT_WIDTH_SHORT;
- }
-}
-
+static UNumberUnitWidth getUnitWidth(UMeasureFormatWidth width) {
+ switch (width) {
+ case UMEASFMT_WIDTH_WIDE:
+ return UNUM_UNIT_WIDTH_FULL_NAME;
+ case UMEASFMT_WIDTH_NARROW:
+ case UMEASFMT_WIDTH_NUMERIC:
+ return UNUM_UNIT_WIDTH_NARROW;
+ case UMEASFMT_WIDTH_SHORT:
+ default:
+ return UNUM_UNIT_WIDTH_SHORT;
+ }
+}
+
/**
* Instances contain all MeasureFormat specific data for a particular locale.
* This data is cached. It is never copied, but is shared via shared pointers.
@@ -147,20 +147,20 @@ public:
}
private:
- NumberFormat* currencyFormats[WIDTH_INDEX_COUNT];
- NumberFormat* integerFormat;
- NumericDateFormatters* numericDateFormatters;
-
+ NumberFormat* currencyFormats[WIDTH_INDEX_COUNT];
+ NumberFormat* integerFormat;
+ NumericDateFormatters* numericDateFormatters;
+
MeasureFormatCacheData(const MeasureFormatCacheData &other);
MeasureFormatCacheData &operator=(const MeasureFormatCacheData &other);
};
-MeasureFormatCacheData::MeasureFormatCacheData()
- : integerFormat(nullptr), numericDateFormatters(nullptr) {
+MeasureFormatCacheData::MeasureFormatCacheData()
+ : integerFormat(nullptr), numericDateFormatters(nullptr) {
for (int32_t i = 0; i < WIDTH_INDEX_COUNT; ++i) {
widthFallback[i] = UMEASFMT_WIDTH_COUNT;
}
- memset(currencyFormats, 0, sizeof(currencyFormats));
+ memset(currencyFormats, 0, sizeof(currencyFormats));
}
MeasureFormatCacheData::~MeasureFormatCacheData() {
@@ -231,7 +231,7 @@ static NumericDateFormatters *loadNumericDateFormatters(
NumericDateFormatters *result = new NumericDateFormatters(
loadNumericDateFormatterPattern(resource, "hm", status),
loadNumericDateFormatterPattern(resource, "ms", status),
- loadNumericDateFormatterPattern(resource, "hms", status));
+ loadNumericDateFormatterPattern(resource, "hms", status));
if (U_FAILURE(status)) {
delete result;
return NULL;
@@ -355,7 +355,7 @@ MeasureFormat::MeasureFormat(
: cache(NULL),
numberFormat(NULL),
pluralRules(NULL),
- fWidth(w),
+ fWidth(w),
listFormatter(NULL) {
initMeasureFormat(locale, w, NULL, status);
}
@@ -368,7 +368,7 @@ MeasureFormat::MeasureFormat(
: cache(NULL),
numberFormat(NULL),
pluralRules(NULL),
- fWidth(w),
+ fWidth(w),
listFormatter(NULL) {
initMeasureFormat(locale, w, nfToAdopt, status);
}
@@ -378,7 +378,7 @@ MeasureFormat::MeasureFormat(const MeasureFormat &other) :
cache(other.cache),
numberFormat(other.numberFormat),
pluralRules(other.pluralRules),
- fWidth(other.fWidth),
+ fWidth(other.fWidth),
listFormatter(NULL) {
cache->addRef();
numberFormat->addRef();
@@ -396,7 +396,7 @@ MeasureFormat &MeasureFormat::operator=(const MeasureFormat &other) {
SharedObject::copyPtr(other.cache, cache);
SharedObject::copyPtr(other.numberFormat, numberFormat);
SharedObject::copyPtr(other.pluralRules, pluralRules);
- fWidth = other.fWidth;
+ fWidth = other.fWidth;
delete listFormatter;
if (other.listFormatter != NULL) {
listFormatter = new ListFormatter(*other.listFormatter);
@@ -410,7 +410,7 @@ MeasureFormat::MeasureFormat() :
cache(NULL),
numberFormat(NULL),
pluralRules(NULL),
- fWidth(UMEASFMT_WIDTH_SHORT),
+ fWidth(UMEASFMT_WIDTH_SHORT),
listFormatter(NULL) {
}
@@ -440,7 +440,7 @@ UBool MeasureFormat::operator==(const Format &other) const {
// don't have to check it here.
// differing widths aren't equivalent
- if (fWidth != rhs.fWidth) {
+ if (fWidth != rhs.fWidth) {
return FALSE;
}
// Width the same check locales.
@@ -463,7 +463,7 @@ UBool MeasureFormat::operator==(const Format &other) const {
**numberFormat == **rhs.numberFormat);
}
-MeasureFormat *MeasureFormat::clone() const {
+MeasureFormat *MeasureFormat::clone() const {
return new MeasureFormat(*this);
}
@@ -501,22 +501,22 @@ UnicodeString &MeasureFormat::formatMeasurePerUnit(
if (U_FAILURE(status)) {
return appendTo;
}
- auto* df = dynamic_cast<const DecimalFormat*>(&getNumberFormatInternal());
- if (df == nullptr) {
- // Don't know how to handle other types of NumberFormat
- status = U_UNSUPPORTED_ERROR;
+ auto* df = dynamic_cast<const DecimalFormat*>(&getNumberFormatInternal());
+ if (df == nullptr) {
+ // Don't know how to handle other types of NumberFormat
+ status = U_UNSUPPORTED_ERROR;
return appendTo;
}
- UFormattedNumberData result;
- if (auto* lnf = df->toNumberFormatter(status)) {
- result.quantity.setToDouble(measure.getNumber().getDouble(status));
- lnf->unit(measure.getUnit())
- .perUnit(perUnit)
- .unitWidth(getUnitWidth(fWidth))
- .formatImpl(&result, status);
+ UFormattedNumberData result;
+ if (auto* lnf = df->toNumberFormatter(status)) {
+ result.quantity.setToDouble(measure.getNumber().getDouble(status));
+ lnf->unit(measure.getUnit())
+ .perUnit(perUnit)
+ .unitWidth(getUnitWidth(fWidth))
+ .formatImpl(&result, status);
}
- DecimalFormat::fieldPositionHelper(result, pos, appendTo.length(), status);
- appendTo.append(result.toTempString(status));
+ DecimalFormat::fieldPositionHelper(result, pos, appendTo.length(), status);
+ appendTo.append(result.toTempString(status));
return appendTo;
}
@@ -535,7 +535,7 @@ UnicodeString &MeasureFormat::formatMeasures(
if (measureCount == 1) {
return formatMeasure(measures[0], **numberFormat, appendTo, pos, status);
}
- if (fWidth == UMEASFMT_WIDTH_NUMERIC) {
+ if (fWidth == UMEASFMT_WIDTH_NUMERIC) {
Formattable hms[3];
int32_t bitMap = toHMS(measures, measureCount, hms, status);
if (bitMap > 0) {
@@ -568,12 +568,12 @@ UnicodeString &MeasureFormat::formatMeasures(
return appendTo;
}
-UnicodeString MeasureFormat::getUnitDisplayName(const MeasureUnit& unit, UErrorCode& status) const {
- return number::impl::LongNameHandler::getUnitDisplayName(
- getLocale(status),
- unit,
- getUnitWidth(fWidth),
- status);
+UnicodeString MeasureFormat::getUnitDisplayName(const MeasureUnit& unit, UErrorCode& status) const {
+ return number::impl::LongNameHandler::getUnitDisplayName(
+ getLocale(status),
+ unit,
+ getUnitWidth(fWidth),
+ status);
}
void MeasureFormat::initMeasureFormat(
@@ -602,7 +602,7 @@ void MeasureFormat::initMeasureFormat(
SharedObject::copyPtr(pr, pluralRules);
pr->removeRef();
if (nf.isNull()) {
- // TODO: Clean this up
+ // TODO: Clean this up
const SharedNumberFormat *shared = NumberFormat::createSharedInstance(
locale, UNUM_DECIMAL, status);
if (U_FAILURE(status)) {
@@ -616,11 +616,11 @@ void MeasureFormat::initMeasureFormat(
return;
}
}
- fWidth = w;
+ fWidth = w;
delete listFormatter;
listFormatter = ListFormatter::createInstance(
locale,
- listStyles[getRegularWidth(fWidth)],
+ listStyles[getRegularWidth(fWidth)],
status);
}
@@ -643,18 +643,18 @@ UBool MeasureFormat::setMeasureFormatLocale(const Locale &locale, UErrorCode &st
if (U_FAILURE(status) || locale == getLocale(status)) {
return FALSE;
}
- initMeasureFormat(locale, fWidth, NULL, status);
+ initMeasureFormat(locale, fWidth, NULL, status);
return U_SUCCESS(status);
}
-const NumberFormat &MeasureFormat::getNumberFormatInternal() const {
+const NumberFormat &MeasureFormat::getNumberFormatInternal() const {
return **numberFormat;
}
-const NumberFormat &MeasureFormat::getCurrencyFormatInternal() const {
- return *cache->getCurrencyFormat(UMEASFMT_WIDTH_NARROW);
-}
-
+const NumberFormat &MeasureFormat::getCurrencyFormatInternal() const {
+ return *cache->getCurrencyFormat(UMEASFMT_WIDTH_NARROW);
+}
+
const PluralRules &MeasureFormat::getPluralRules() const {
return **pluralRules;
}
@@ -681,142 +681,142 @@ UnicodeString &MeasureFormat::formatMeasure(
if (isCurrency(amtUnit)) {
UChar isoCode[4];
u_charsToUChars(amtUnit.getSubtype(), isoCode, 4);
- return cache->getCurrencyFormat(fWidth)->format(
+ return cache->getCurrencyFormat(fWidth)->format(
new CurrencyAmount(amtNumber, isoCode, status),
appendTo,
pos,
status);
}
- auto* df = dynamic_cast<const DecimalFormat*>(&nf);
- if (df == nullptr) {
- // Handle other types of NumberFormat using the ICU 63 code, modified to
- // get the unitPattern from LongNameHandler and handle fallback to OTHER.
- UnicodeString formattedNumber;
- StandardPlural::Form pluralForm = QuantityFormatter::selectPlural(
- amtNumber, nf, **pluralRules, formattedNumber, pos, status);
- UnicodeString pattern = number::impl::LongNameHandler::getUnitPattern(getLocale(status),
- amtUnit, getUnitWidth(fWidth), pluralForm, status);
- // The above handles fallback from other widths to short, and from other plural forms to OTHER
- if (U_FAILURE(status)) {
- return appendTo;
- }
- SimpleFormatter formatter(pattern, 0, 1, status);
- return QuantityFormatter::format(formatter, formattedNumber, appendTo, pos, status);
- }
- UFormattedNumberData result;
- if (auto* lnf = df->toNumberFormatter(status)) {
- result.quantity.setToDouble(amtNumber.getDouble(status));
- lnf->unit(amtUnit)
- .unitWidth(getUnitWidth(fWidth))
- .formatImpl(&result, status);
- }
- DecimalFormat::fieldPositionHelper(result, pos, appendTo.length(), status);
- appendTo.append(result.toTempString(status));
- return appendTo;
-}
-
-
-// Formats numeric time duration as 5:00:47 or 3:54.
+ auto* df = dynamic_cast<const DecimalFormat*>(&nf);
+ if (df == nullptr) {
+ // Handle other types of NumberFormat using the ICU 63 code, modified to
+ // get the unitPattern from LongNameHandler and handle fallback to OTHER.
+ UnicodeString formattedNumber;
+ StandardPlural::Form pluralForm = QuantityFormatter::selectPlural(
+ amtNumber, nf, **pluralRules, formattedNumber, pos, status);
+ UnicodeString pattern = number::impl::LongNameHandler::getUnitPattern(getLocale(status),
+ amtUnit, getUnitWidth(fWidth), pluralForm, status);
+ // The above handles fallback from other widths to short, and from other plural forms to OTHER
+ if (U_FAILURE(status)) {
+ return appendTo;
+ }
+ SimpleFormatter formatter(pattern, 0, 1, status);
+ return QuantityFormatter::format(formatter, formattedNumber, appendTo, pos, status);
+ }
+ UFormattedNumberData result;
+ if (auto* lnf = df->toNumberFormatter(status)) {
+ result.quantity.setToDouble(amtNumber.getDouble(status));
+ lnf->unit(amtUnit)
+ .unitWidth(getUnitWidth(fWidth))
+ .formatImpl(&result, status);
+ }
+ DecimalFormat::fieldPositionHelper(result, pos, appendTo.length(), status);
+ appendTo.append(result.toTempString(status));
+ return appendTo;
+}
+
+
+// Formats numeric time duration as 5:00:47 or 3:54.
UnicodeString &MeasureFormat::formatNumeric(
const Formattable *hms, // always length 3
- int32_t bitMap, // 1=hour set, 2=minute set, 4=second set
+ int32_t bitMap, // 1=hour set, 2=minute set, 4=second set
UnicodeString &appendTo,
UErrorCode &status) const {
if (U_FAILURE(status)) {
return appendTo;
}
- UnicodeString pattern;
+ UnicodeString pattern;
- double hours = hms[0].getDouble(status);
- double minutes = hms[1].getDouble(status);
- double seconds = hms[2].getDouble(status);
+ double hours = hms[0].getDouble(status);
+ double minutes = hms[1].getDouble(status);
+ double seconds = hms[2].getDouble(status);
if (U_FAILURE(status)) {
return appendTo;
}
- // All possible combinations: "h", "m", "s", "hm", "hs", "ms", "hms"
- if (bitMap == 5 || bitMap == 7) { // "hms" & "hs" (we add minutes if "hs")
- pattern = cache->getNumericDateFormatters()->hourMinuteSecond;
- hours = uprv_trunc(hours);
- minutes = uprv_trunc(minutes);
- } else if (bitMap == 3) { // "hm"
- pattern = cache->getNumericDateFormatters()->hourMinute;
- hours = uprv_trunc(hours);
- } else if (bitMap == 6) { // "ms"
- pattern = cache->getNumericDateFormatters()->minuteSecond;
- minutes = uprv_trunc(minutes);
- } else { // h m s, handled outside formatNumeric. No value is also an error.
+ // All possible combinations: "h", "m", "s", "hm", "hs", "ms", "hms"
+ if (bitMap == 5 || bitMap == 7) { // "hms" & "hs" (we add minutes if "hs")
+ pattern = cache->getNumericDateFormatters()->hourMinuteSecond;
+ hours = uprv_trunc(hours);
+ minutes = uprv_trunc(minutes);
+ } else if (bitMap == 3) { // "hm"
+ pattern = cache->getNumericDateFormatters()->hourMinute;
+ hours = uprv_trunc(hours);
+ } else if (bitMap == 6) { // "ms"
+ pattern = cache->getNumericDateFormatters()->minuteSecond;
+ minutes = uprv_trunc(minutes);
+ } else { // h m s, handled outside formatNumeric. No value is also an error.
status = U_INTERNAL_PROGRAM_ERROR;
return appendTo;
}
- const DecimalFormat *numberFormatter = dynamic_cast<const DecimalFormat*>(numberFormat->get());
- if (!numberFormatter) {
- status = U_INTERNAL_PROGRAM_ERROR;
- return appendTo;
- }
- number::LocalizedNumberFormatter numberFormatter2;
- if (auto* lnf = numberFormatter->toNumberFormatter(status)) {
- numberFormatter2 = lnf->integerWidth(number::IntegerWidth::zeroFillTo(2));
+ const DecimalFormat *numberFormatter = dynamic_cast<const DecimalFormat*>(numberFormat->get());
+ if (!numberFormatter) {
+ status = U_INTERNAL_PROGRAM_ERROR;
+ return appendTo;
+ }
+ number::LocalizedNumberFormatter numberFormatter2;
+ if (auto* lnf = numberFormatter->toNumberFormatter(status)) {
+ numberFormatter2 = lnf->integerWidth(number::IntegerWidth::zeroFillTo(2));
} else {
- return appendTo;
+ return appendTo;
}
- FormattedStringBuilder fsb;
+ FormattedStringBuilder fsb;
- UBool protect = FALSE;
- const int32_t patternLength = pattern.length();
- for (int32_t i = 0; i < patternLength; i++) {
- char16_t c = pattern[i];
+ UBool protect = FALSE;
+ const int32_t patternLength = pattern.length();
+ for (int32_t i = 0; i < patternLength; i++) {
+ char16_t c = pattern[i];
- // Also set the proper field in this switch
- // We don't use DateFormat.Field because this is not a date / time, is a duration.
- double value = 0;
- switch (c) {
- case u'H': value = hours; break;
- case u'm': value = minutes; break;
- case u's': value = seconds; break;
+ // Also set the proper field in this switch
+ // We don't use DateFormat.Field because this is not a date / time, is a duration.
+ double value = 0;
+ switch (c) {
+ case u'H': value = hours; break;
+ case u'm': value = minutes; break;
+ case u's': value = seconds; break;
}
- // There is not enough info to add Field(s) for the unit because all we have are plain
- // text patterns. For example in "21:51" there is no text for something like "hour",
- // while in something like "21h51" there is ("h"). But we can't really tell...
- switch (c) {
- case u'H':
- case u'm':
- case u's':
- if (protect) {
- fsb.appendChar16(c, kUndefinedField, status);
- } else {
- UnicodeString tmp;
- if ((i + 1 < patternLength) && pattern[i + 1] == c) { // doubled
- tmp = numberFormatter2.formatDouble(value, status).toString(status);
- i++;
- } else {
- numberFormatter->format(value, tmp, status);
- }
- // TODO: Use proper Field
- fsb.append(tmp, kUndefinedField, status);
- }
- break;
- case u'\'':
- // '' is escaped apostrophe
- if ((i + 1 < patternLength) && pattern[i + 1] == c) {
- fsb.appendChar16(c, kUndefinedField, status);
- i++;
- } else {
- protect = !protect;
- }
- break;
- default:
- fsb.appendChar16(c, kUndefinedField, status);
- }
- }
-
- appendTo.append(fsb.toTempUnicodeString());
-
- return appendTo;
+ // There is not enough info to add Field(s) for the unit because all we have are plain
+ // text patterns. For example in "21:51" there is no text for something like "hour",
+ // while in something like "21h51" there is ("h"). But we can't really tell...
+ switch (c) {
+ case u'H':
+ case u'm':
+ case u's':
+ if (protect) {
+ fsb.appendChar16(c, kUndefinedField, status);
+ } else {
+ UnicodeString tmp;
+ if ((i + 1 < patternLength) && pattern[i + 1] == c) { // doubled
+ tmp = numberFormatter2.formatDouble(value, status).toString(status);
+ i++;
+ } else {
+ numberFormatter->format(value, tmp, status);
+ }
+ // TODO: Use proper Field
+ fsb.append(tmp, kUndefinedField, status);
+ }
+ break;
+ case u'\'':
+ // '' is escaped apostrophe
+ if ((i + 1 < patternLength) && pattern[i + 1] == c) {
+ fsb.appendChar16(c, kUndefinedField, status);
+ i++;
+ } else {
+ protect = !protect;
+ }
+ break;
+ default:
+ fsb.appendChar16(c, kUndefinedField, status);
+ }
+ }
+
+ appendTo.append(fsb.toTempUnicodeString());
+
+ return appendTo;
}
UnicodeString &MeasureFormat::formatMeasuresSlowTrack(
@@ -830,7 +830,7 @@ UnicodeString &MeasureFormat::formatMeasuresSlowTrack(
}
FieldPosition dontCare(FieldPosition::DONT_CARE);
FieldPosition fpos(pos.getField());
- LocalArray<UnicodeString> results(new UnicodeString[measureCount], status);
+ LocalArray<UnicodeString> results(new UnicodeString[measureCount], status);
int32_t fieldPositionFoundIndex = -1;
for (int32_t i = 0; i < measureCount; ++i) {
const NumberFormat *nf = cache->getIntegerFormat();
@@ -851,7 +851,7 @@ UnicodeString &MeasureFormat::formatMeasuresSlowTrack(
}
int32_t offset;
listFormatter->format(
- results.getAlias(),
+ results.getAlias(),
measureCount,
appendTo,
fieldPositionFoundIndex,
@@ -860,7 +860,7 @@ UnicodeString &MeasureFormat::formatMeasuresSlowTrack(
if (U_FAILURE(status)) {
return appendTo;
}
- // Fix up FieldPosition indexes if our field is found.
+ // Fix up FieldPosition indexes if our field is found.
if (offset != -1) {
pos.setBeginIndex(fpos.getBeginIndex() + offset);
pos.setEndIndex(fpos.getEndIndex() + offset);
@@ -870,16 +870,16 @@ UnicodeString &MeasureFormat::formatMeasuresSlowTrack(
MeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(const Locale& locale,
UErrorCode& ec) {
- if (U_FAILURE(ec)) {
- return nullptr;
+ if (U_FAILURE(ec)) {
+ return nullptr;
}
- LocalPointer<CurrencyFormat> fmt(new CurrencyFormat(locale, ec), ec);
- return fmt.orphan();
+ LocalPointer<CurrencyFormat> fmt(new CurrencyFormat(locale, ec), ec);
+ return fmt.orphan();
}
MeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(UErrorCode& ec) {
if (U_FAILURE(ec)) {
- return nullptr;
+ return nullptr;
}
return MeasureFormat::createCurrencyFormat(Locale::getDefault(), ec);
}
diff --git a/contrib/libs/icu/i18n/measunit.cpp b/contrib/libs/icu/i18n/measunit.cpp
index 4edf130b7e..cce8f5eb16 100644
--- a/contrib/libs/icu/i18n/measunit.cpp
+++ b/contrib/libs/icu/i18n/measunit.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -17,11 +17,11 @@
#if !UCONFIG_NO_FORMATTING
#include "unicode/uenum.h"
-#include "unicode/errorcode.h"
+#include "unicode/errorcode.h"
#include "ustrenum.h"
#include "cstring.h"
#include "uassert.h"
-#include "measunit_impl.h"
+#include "measunit_impl.h"
U_NAMESPACE_BEGIN
@@ -35,59 +35,59 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MeasureUnit)
//
// Start generated code
-
+
static const int32_t gOffsets[] = {
0,
2,
7,
- 17,
- 25,
- 29,
- 328,
- 339,
- 355,
- 359,
- 368,
- 370,
- 374,
- 381,
- 402,
- 404,
- 418,
- 421,
- 427,
- 437,
- 441,
- 445,
- 447,
- 474
+ 17,
+ 25,
+ 29,
+ 328,
+ 339,
+ 355,
+ 359,
+ 368,
+ 370,
+ 374,
+ 381,
+ 402,
+ 404,
+ 418,
+ 421,
+ 427,
+ 437,
+ 441,
+ 445,
+ 447,
+ 474
};
static const int32_t gIndexes[] = {
0,
2,
7,
- 17,
- 25,
- 29,
- 29,
- 40,
- 56,
- 60,
- 69,
- 71,
- 75,
+ 17,
+ 25,
+ 29,
+ 29,
+ 40,
+ 56,
+ 60,
+ 69,
+ 71,
+ 75,
82,
- 103,
+ 103,
105,
- 119,
- 122,
- 128,
- 138,
- 142,
- 146,
- 148,
- 175
+ 119,
+ 122,
+ 128,
+ 138,
+ 142,
+ 146,
+ 148,
+ 175
};
// Must be sorted alphabetically.
@@ -102,32 +102,32 @@ static const char * const gTypes[] = {
"duration",
"electric",
"energy",
- "force",
+ "force",
"frequency",
- "graphics",
+ "graphics",
"length",
"light",
"mass",
- "none",
+ "none",
"power",
"pressure",
"speed",
"temperature",
- "torque",
+ "torque",
"volume"
};
// Must be grouped by type and sorted alphabetically within each type.
static const char * const gSubTypes[] = {
"g-force",
- "meter-per-square-second",
+ "meter-per-square-second",
"arc-minute",
"arc-second",
"degree",
"radian",
"revolution",
"acre",
- "dunam",
+ "dunam",
"hectare",
"square-centimeter",
"square-foot",
@@ -139,12 +139,12 @@ static const char * const gSubTypes[] = {
"karat",
"milligram-per-deciliter",
"millimole-per-liter",
- "mole",
- "percent",
- "permille",
- "permillion",
- "permyriad",
- "liter-per-100-kilometer",
+ "mole",
+ "percent",
+ "permille",
+ "permillion",
+ "permyriad",
+ "liter-per-100-kilometer",
"liter-per-kilometer",
"mile-per-gallon",
"mile-per-gallon-imperial",
@@ -152,18 +152,18 @@ static const char * const gSubTypes[] = {
"AED",
"AFA",
"AFN",
- "ALK",
+ "ALK",
"ALL",
"AMD",
"ANG",
"AOA",
- "AOK",
+ "AOK",
"AON",
"AOR",
"ARA",
"ARP",
"ARS",
- "ARY",
+ "ARY",
"ATS",
"AUD",
"AWG",
@@ -177,8 +177,8 @@ static const char * const gSubTypes[] = {
"BEC",
"BEF",
"BEL",
- "BGJ",
- "BGK",
+ "BGJ",
+ "BGK",
"BGL",
"BGN",
"BHD",
@@ -186,9 +186,9 @@ static const char * const gSubTypes[] = {
"BMD",
"BND",
"BOB",
- "BOP",
+ "BOP",
"BOV",
- "BRB",
+ "BRB",
"BRC",
"BRE",
"BRL",
@@ -196,10 +196,10 @@ static const char * const gSubTypes[] = {
"BRR",
"BSD",
"BTN",
- "BUK",
+ "BUK",
"BWP",
"BYB",
- "BYN",
+ "BYN",
"BYR",
"BZD",
"CAD",
@@ -215,7 +215,7 @@ static const char * const gSubTypes[] = {
"COU",
"CRC",
"CSD",
- "CSJ",
+ "CSJ",
"CSK",
"CUC",
"CUP",
@@ -250,13 +250,13 @@ static const char * const gSubTypes[] = {
"GHS",
"GIP",
"GMD",
- "GNE",
+ "GNE",
"GNF",
- "GNS",
+ "GNS",
"GQE",
"GRD",
"GTQ",
- "GWE",
+ "GWE",
"GWP",
"GYD",
"HKD",
@@ -267,13 +267,13 @@ static const char * const gSubTypes[] = {
"HUF",
"IDR",
"IEP",
- "ILP",
- "ILR",
+ "ILP",
+ "ILR",
"ILS",
"INR",
"IQD",
"IRR",
- "ISJ",
+ "ISJ",
"ISK",
"ITL",
"JMD",
@@ -288,13 +288,13 @@ static const char * const gSubTypes[] = {
"KWD",
"KYD",
"KZT",
- "LAJ",
+ "LAJ",
"LAK",
"LBP",
"LKR",
"LRD",
"LSL",
- "LSM",
+ "LSM",
"LTL",
"LTT",
"LUC",
@@ -313,23 +313,23 @@ static const char * const gSubTypes[] = {
"MNT",
"MOP",
"MRO",
- "MRU",
+ "MRU",
"MTL",
- "MTP",
+ "MTP",
"MUR",
- "MVQ",
+ "MVQ",
"MVR",
"MWK",
"MXN",
- "MXP",
+ "MXP",
"MXV",
"MYR",
- "MZE",
+ "MZE",
"MZM",
"MZN",
"NAD",
"NGN",
- "NIC",
+ "NIC",
"NIO",
"NLG",
"NOK",
@@ -337,7 +337,7 @@ static const char * const gSubTypes[] = {
"NZD",
"OMR",
"PAB",
- "PEH",
+ "PEH",
"PEI",
"PEN",
"PES",
@@ -349,8 +349,8 @@ static const char * const gSubTypes[] = {
"PTE",
"PYG",
"QAR",
- "RHD",
- "ROK",
+ "RHD",
+ "ROK",
"ROL",
"RON",
"RSD",
@@ -362,7 +362,7 @@ static const char * const gSubTypes[] = {
"SCR",
"SDD",
"SDG",
- "SDP",
+ "SDP",
"SEK",
"SGD",
"SHP",
@@ -374,8 +374,8 @@ static const char * const gSubTypes[] = {
"SRG",
"SSP",
"STD",
- "STN",
- "SUR",
+ "STN",
+ "SUR",
"SVC",
"SYP",
"SZL",
@@ -394,22 +394,22 @@ static const char * const gSubTypes[] = {
"TZS",
"UAH",
"UAK",
- "UGS",
- "UGW",
+ "UGS",
+ "UGW",
"UGX",
"USD",
"USN",
"USS",
"UYI",
- "UYN",
- "UYP",
+ "UYN",
+ "UYP",
"UYU",
- "UYW",
+ "UYW",
"UZS",
"VEB",
"VEF",
- "VES",
- "VNC",
+ "VES",
+ "VNC",
"VND",
"VUV",
"WST",
@@ -433,7 +433,7 @@ static const char * const gSubTypes[] = {
"XXX",
"YDD",
"YER",
- "YUD",
+ "YUD",
"YUM",
"YUN",
"ZAL",
@@ -442,7 +442,7 @@ static const char * const gSubTypes[] = {
"ZMW",
"ZRN",
"ZRZ",
- "ZWC",
+ "ZWC",
"ZWD",
"ZWL",
"ZWN",
@@ -455,51 +455,51 @@ static const char * const gSubTypes[] = {
"kilobyte",
"megabit",
"megabyte",
- "petabyte",
+ "petabyte",
"terabit",
"terabyte",
"century",
"day",
- "day-person",
- "decade",
+ "day-person",
+ "decade",
"hour",
"microsecond",
"millisecond",
"minute",
"month",
- "month-person",
+ "month-person",
"nanosecond",
"second",
"week",
- "week-person",
+ "week-person",
"year",
- "year-person",
+ "year-person",
"ampere",
"milliampere",
"ohm",
"volt",
- "british-thermal-unit",
+ "british-thermal-unit",
"calorie",
- "electronvolt",
+ "electronvolt",
"foodcalorie",
"joule",
"kilocalorie",
"kilojoule",
"kilowatt-hour",
- "therm-us",
- "newton",
- "pound-force",
+ "therm-us",
+ "newton",
+ "pound-force",
"gigahertz",
"hertz",
"kilohertz",
"megahertz",
- "dot-per-centimeter",
- "dot-per-inch",
- "em",
- "megapixel",
- "pixel",
- "pixel-per-centimeter",
- "pixel-per-inch",
+ "dot-per-centimeter",
+ "dot-per-inch",
+ "em",
+ "megapixel",
+ "pixel",
+ "pixel-per-centimeter",
+ "pixel-per-inch",
"astronomical-unit",
"centimeter",
"decimeter",
@@ -518,14 +518,14 @@ static const char * const gSubTypes[] = {
"nautical-mile",
"parsec",
"picometer",
- "point",
- "solar-radius",
+ "point",
+ "solar-radius",
"yard",
"lux",
- "solar-luminosity",
+ "solar-luminosity",
"carat",
- "dalton",
- "earth-mass",
+ "dalton",
+ "earth-mass",
"gram",
"kilogram",
"metric-ton",
@@ -534,28 +534,28 @@ static const char * const gSubTypes[] = {
"ounce",
"ounce-troy",
"pound",
- "solar-mass",
+ "solar-mass",
"stone",
"ton",
- "", // TODO(ICU-21076): manual edit of what should have been generated by Java.
- "percent", // TODO(ICU-21076): regenerate, deal with duplication.
- "permille", // TODO(ICU-21076): regenerate, deal with duplication.
+ "", // TODO(ICU-21076): manual edit of what should have been generated by Java.
+ "percent", // TODO(ICU-21076): regenerate, deal with duplication.
+ "permille", // TODO(ICU-21076): regenerate, deal with duplication.
"gigawatt",
"horsepower",
"kilowatt",
"megawatt",
"milliwatt",
"watt",
- "atmosphere",
- "bar",
+ "atmosphere",
+ "bar",
"hectopascal",
- "inch-ofhg",
- "kilopascal",
- "megapascal",
+ "inch-ofhg",
+ "kilopascal",
+ "megapascal",
"millibar",
- "millimeter-ofhg",
- "pascal",
- "pound-force-per-square-inch",
+ "millimeter-ofhg",
+ "pascal",
+ "pound-force-per-square-inch",
"kilometer-per-hour",
"knot",
"meter-per-second",
@@ -564,10 +564,10 @@ static const char * const gSubTypes[] = {
"fahrenheit",
"generic",
"kelvin",
- "newton-meter",
- "pound-force-foot",
+ "newton-meter",
+ "pound-force-foot",
"acre-foot",
- "barrel",
+ "barrel",
"bushel",
"centiliter",
"cubic-centimeter",
@@ -581,7 +581,7 @@ static const char * const gSubTypes[] = {
"cup-metric",
"deciliter",
"fluid-ounce",
- "fluid-ounce-imperial",
+ "fluid-ounce-imperial",
"gallon",
"gallon-imperial",
"hectoliter",
@@ -597,1405 +597,1405 @@ static const char * const gSubTypes[] = {
// Must be sorted by first value and then second value.
static int32_t unitPerUnitToSingleUnit[][4] = {
- {378, 382, 12, 5},
- {378, 387, 12, 6},
- {388, 343, 19, 0},
- {390, 350, 19, 2},
- {392, 343, 19, 3},
- {392, 463, 4, 2},
- {392, 464, 4, 3},
- {411, 460, 3, 1},
- {414, 12, 18, 9},
- {466, 388, 4, 1}
+ {378, 382, 12, 5},
+ {378, 387, 12, 6},
+ {388, 343, 19, 0},
+ {390, 350, 19, 2},
+ {392, 343, 19, 3},
+ {392, 463, 4, 2},
+ {392, 464, 4, 3},
+ {411, 460, 3, 1},
+ {414, 12, 18, 9},
+ {466, 388, 4, 1}
};
-// Shortcuts to the base unit in order to make the default constructor fast
-static const int32_t kBaseTypeIdx = 16;
-static const int32_t kBaseSubTypeIdx = 0;
-
+// Shortcuts to the base unit in order to make the default constructor fast
+static const int32_t kBaseTypeIdx = 16;
+static const int32_t kBaseSubTypeIdx = 0;
+
MeasureUnit *MeasureUnit::createGForce(UErrorCode &status) {
return MeasureUnit::create(0, 0, status);
}
-MeasureUnit MeasureUnit::getGForce() {
- return MeasureUnit(0, 0);
-}
-
+MeasureUnit MeasureUnit::getGForce() {
+ return MeasureUnit(0, 0);
+}
+
MeasureUnit *MeasureUnit::createMeterPerSecondSquared(UErrorCode &status) {
return MeasureUnit::create(0, 1, status);
}
-MeasureUnit MeasureUnit::getMeterPerSecondSquared() {
- return MeasureUnit(0, 1);
-}
-
+MeasureUnit MeasureUnit::getMeterPerSecondSquared() {
+ return MeasureUnit(0, 1);
+}
+
MeasureUnit *MeasureUnit::createArcMinute(UErrorCode &status) {
return MeasureUnit::create(1, 0, status);
}
-MeasureUnit MeasureUnit::getArcMinute() {
- return MeasureUnit(1, 0);
-}
-
+MeasureUnit MeasureUnit::getArcMinute() {
+ return MeasureUnit(1, 0);
+}
+
MeasureUnit *MeasureUnit::createArcSecond(UErrorCode &status) {
return MeasureUnit::create(1, 1, status);
}
-MeasureUnit MeasureUnit::getArcSecond() {
- return MeasureUnit(1, 1);
-}
-
+MeasureUnit MeasureUnit::getArcSecond() {
+ return MeasureUnit(1, 1);
+}
+
MeasureUnit *MeasureUnit::createDegree(UErrorCode &status) {
return MeasureUnit::create(1, 2, status);
}
-MeasureUnit MeasureUnit::getDegree() {
- return MeasureUnit(1, 2);
-}
-
+MeasureUnit MeasureUnit::getDegree() {
+ return MeasureUnit(1, 2);
+}
+
MeasureUnit *MeasureUnit::createRadian(UErrorCode &status) {
return MeasureUnit::create(1, 3, status);
}
-MeasureUnit MeasureUnit::getRadian() {
- return MeasureUnit(1, 3);
-}
-
+MeasureUnit MeasureUnit::getRadian() {
+ return MeasureUnit(1, 3);
+}
+
MeasureUnit *MeasureUnit::createRevolutionAngle(UErrorCode &status) {
return MeasureUnit::create(1, 4, status);
}
-MeasureUnit MeasureUnit::getRevolutionAngle() {
- return MeasureUnit(1, 4);
-}
-
+MeasureUnit MeasureUnit::getRevolutionAngle() {
+ return MeasureUnit(1, 4);
+}
+
MeasureUnit *MeasureUnit::createAcre(UErrorCode &status) {
return MeasureUnit::create(2, 0, status);
}
-MeasureUnit MeasureUnit::getAcre() {
- return MeasureUnit(2, 0);
-}
-
-MeasureUnit *MeasureUnit::createDunam(UErrorCode &status) {
+MeasureUnit MeasureUnit::getAcre() {
+ return MeasureUnit(2, 0);
+}
+
+MeasureUnit *MeasureUnit::createDunam(UErrorCode &status) {
return MeasureUnit::create(2, 1, status);
}
-MeasureUnit MeasureUnit::getDunam() {
- return MeasureUnit(2, 1);
-}
-
-MeasureUnit *MeasureUnit::createHectare(UErrorCode &status) {
+MeasureUnit MeasureUnit::getDunam() {
+ return MeasureUnit(2, 1);
+}
+
+MeasureUnit *MeasureUnit::createHectare(UErrorCode &status) {
return MeasureUnit::create(2, 2, status);
}
-MeasureUnit MeasureUnit::getHectare() {
- return MeasureUnit(2, 2);
-}
-
-MeasureUnit *MeasureUnit::createSquareCentimeter(UErrorCode &status) {
+MeasureUnit MeasureUnit::getHectare() {
+ return MeasureUnit(2, 2);
+}
+
+MeasureUnit *MeasureUnit::createSquareCentimeter(UErrorCode &status) {
return MeasureUnit::create(2, 3, status);
}
-MeasureUnit MeasureUnit::getSquareCentimeter() {
- return MeasureUnit(2, 3);
-}
-
-MeasureUnit *MeasureUnit::createSquareFoot(UErrorCode &status) {
+MeasureUnit MeasureUnit::getSquareCentimeter() {
+ return MeasureUnit(2, 3);
+}
+
+MeasureUnit *MeasureUnit::createSquareFoot(UErrorCode &status) {
return MeasureUnit::create(2, 4, status);
}
-MeasureUnit MeasureUnit::getSquareFoot() {
- return MeasureUnit(2, 4);
-}
-
-MeasureUnit *MeasureUnit::createSquareInch(UErrorCode &status) {
+MeasureUnit MeasureUnit::getSquareFoot() {
+ return MeasureUnit(2, 4);
+}
+
+MeasureUnit *MeasureUnit::createSquareInch(UErrorCode &status) {
return MeasureUnit::create(2, 5, status);
}
-MeasureUnit MeasureUnit::getSquareInch() {
- return MeasureUnit(2, 5);
-}
-
-MeasureUnit *MeasureUnit::createSquareKilometer(UErrorCode &status) {
+MeasureUnit MeasureUnit::getSquareInch() {
+ return MeasureUnit(2, 5);
+}
+
+MeasureUnit *MeasureUnit::createSquareKilometer(UErrorCode &status) {
return MeasureUnit::create(2, 6, status);
}
-MeasureUnit MeasureUnit::getSquareKilometer() {
- return MeasureUnit(2, 6);
-}
-
-MeasureUnit *MeasureUnit::createSquareMeter(UErrorCode &status) {
+MeasureUnit MeasureUnit::getSquareKilometer() {
+ return MeasureUnit(2, 6);
+}
+
+MeasureUnit *MeasureUnit::createSquareMeter(UErrorCode &status) {
return MeasureUnit::create(2, 7, status);
}
-MeasureUnit MeasureUnit::getSquareMeter() {
- return MeasureUnit(2, 7);
-}
-
-MeasureUnit *MeasureUnit::createSquareMile(UErrorCode &status) {
+MeasureUnit MeasureUnit::getSquareMeter() {
+ return MeasureUnit(2, 7);
+}
+
+MeasureUnit *MeasureUnit::createSquareMile(UErrorCode &status) {
return MeasureUnit::create(2, 8, status);
}
-MeasureUnit MeasureUnit::getSquareMile() {
- return MeasureUnit(2, 8);
-}
-
-MeasureUnit *MeasureUnit::createSquareYard(UErrorCode &status) {
- return MeasureUnit::create(2, 9, status);
-}
-
-MeasureUnit MeasureUnit::getSquareYard() {
- return MeasureUnit(2, 9);
-}
-
+MeasureUnit MeasureUnit::getSquareMile() {
+ return MeasureUnit(2, 8);
+}
+
+MeasureUnit *MeasureUnit::createSquareYard(UErrorCode &status) {
+ return MeasureUnit::create(2, 9, status);
+}
+
+MeasureUnit MeasureUnit::getSquareYard() {
+ return MeasureUnit(2, 9);
+}
+
MeasureUnit *MeasureUnit::createKarat(UErrorCode &status) {
return MeasureUnit::create(3, 0, status);
}
-MeasureUnit MeasureUnit::getKarat() {
- return MeasureUnit(3, 0);
-}
-
+MeasureUnit MeasureUnit::getKarat() {
+ return MeasureUnit(3, 0);
+}
+
MeasureUnit *MeasureUnit::createMilligramPerDeciliter(UErrorCode &status) {
return MeasureUnit::create(3, 1, status);
}
-MeasureUnit MeasureUnit::getMilligramPerDeciliter() {
- return MeasureUnit(3, 1);
-}
-
+MeasureUnit MeasureUnit::getMilligramPerDeciliter() {
+ return MeasureUnit(3, 1);
+}
+
MeasureUnit *MeasureUnit::createMillimolePerLiter(UErrorCode &status) {
return MeasureUnit::create(3, 2, status);
}
-MeasureUnit MeasureUnit::getMillimolePerLiter() {
- return MeasureUnit(3, 2);
-}
-
-MeasureUnit *MeasureUnit::createMole(UErrorCode &status) {
+MeasureUnit MeasureUnit::getMillimolePerLiter() {
+ return MeasureUnit(3, 2);
+}
+
+MeasureUnit *MeasureUnit::createMole(UErrorCode &status) {
return MeasureUnit::create(3, 3, status);
}
-MeasureUnit MeasureUnit::getMole() {
- return MeasureUnit(3, 3);
-}
-
-MeasureUnit *MeasureUnit::createPartPerMillion(UErrorCode &status) {
- return MeasureUnit::create(3, 6, status);
-}
-
-MeasureUnit MeasureUnit::getPartPerMillion() {
- return MeasureUnit(3, 6);
-}
-
-MeasureUnit *MeasureUnit::createPercent(UErrorCode &status) {
- return MeasureUnit::create(3, 4, status);
-}
-
-MeasureUnit MeasureUnit::getPercent() {
- return MeasureUnit(3, 4);
-}
-
-MeasureUnit *MeasureUnit::createPermille(UErrorCode &status) {
- return MeasureUnit::create(3, 5, status);
-}
-
-MeasureUnit MeasureUnit::getPermille() {
- return MeasureUnit(3, 5);
-}
-
-MeasureUnit *MeasureUnit::createPermyriad(UErrorCode &status) {
- return MeasureUnit::create(3, 7, status);
-}
-
-MeasureUnit MeasureUnit::getPermyriad() {
- return MeasureUnit(3, 7);
-}
-
+MeasureUnit MeasureUnit::getMole() {
+ return MeasureUnit(3, 3);
+}
+
+MeasureUnit *MeasureUnit::createPartPerMillion(UErrorCode &status) {
+ return MeasureUnit::create(3, 6, status);
+}
+
+MeasureUnit MeasureUnit::getPartPerMillion() {
+ return MeasureUnit(3, 6);
+}
+
+MeasureUnit *MeasureUnit::createPercent(UErrorCode &status) {
+ return MeasureUnit::create(3, 4, status);
+}
+
+MeasureUnit MeasureUnit::getPercent() {
+ return MeasureUnit(3, 4);
+}
+
+MeasureUnit *MeasureUnit::createPermille(UErrorCode &status) {
+ return MeasureUnit::create(3, 5, status);
+}
+
+MeasureUnit MeasureUnit::getPermille() {
+ return MeasureUnit(3, 5);
+}
+
+MeasureUnit *MeasureUnit::createPermyriad(UErrorCode &status) {
+ return MeasureUnit::create(3, 7, status);
+}
+
+MeasureUnit MeasureUnit::getPermyriad() {
+ return MeasureUnit(3, 7);
+}
+
MeasureUnit *MeasureUnit::createLiterPer100Kilometers(UErrorCode &status) {
return MeasureUnit::create(4, 0, status);
}
-MeasureUnit MeasureUnit::getLiterPer100Kilometers() {
- return MeasureUnit(4, 0);
-}
-
+MeasureUnit MeasureUnit::getLiterPer100Kilometers() {
+ return MeasureUnit(4, 0);
+}
+
MeasureUnit *MeasureUnit::createLiterPerKilometer(UErrorCode &status) {
return MeasureUnit::create(4, 1, status);
}
-MeasureUnit MeasureUnit::getLiterPerKilometer() {
- return MeasureUnit(4, 1);
-}
-
+MeasureUnit MeasureUnit::getLiterPerKilometer() {
+ return MeasureUnit(4, 1);
+}
+
MeasureUnit *MeasureUnit::createMilePerGallon(UErrorCode &status) {
return MeasureUnit::create(4, 2, status);
}
-MeasureUnit MeasureUnit::getMilePerGallon() {
- return MeasureUnit(4, 2);
-}
-
+MeasureUnit MeasureUnit::getMilePerGallon() {
+ return MeasureUnit(4, 2);
+}
+
MeasureUnit *MeasureUnit::createMilePerGallonImperial(UErrorCode &status) {
return MeasureUnit::create(4, 3, status);
}
-MeasureUnit MeasureUnit::getMilePerGallonImperial() {
- return MeasureUnit(4, 3);
+MeasureUnit MeasureUnit::getMilePerGallonImperial() {
+ return MeasureUnit(4, 3);
}
-MeasureUnit *MeasureUnit::createBit(UErrorCode &status) {
- return MeasureUnit::create(6, 0, status);
+MeasureUnit *MeasureUnit::createBit(UErrorCode &status) {
+ return MeasureUnit::create(6, 0, status);
}
-MeasureUnit MeasureUnit::getBit() {
- return MeasureUnit(6, 0);
+MeasureUnit MeasureUnit::getBit() {
+ return MeasureUnit(6, 0);
}
-MeasureUnit *MeasureUnit::createByte(UErrorCode &status) {
- return MeasureUnit::create(6, 1, status);
+MeasureUnit *MeasureUnit::createByte(UErrorCode &status) {
+ return MeasureUnit::create(6, 1, status);
}
-MeasureUnit MeasureUnit::getByte() {
- return MeasureUnit(6, 1);
+MeasureUnit MeasureUnit::getByte() {
+ return MeasureUnit(6, 1);
}
-MeasureUnit *MeasureUnit::createGigabit(UErrorCode &status) {
- return MeasureUnit::create(6, 2, status);
+MeasureUnit *MeasureUnit::createGigabit(UErrorCode &status) {
+ return MeasureUnit::create(6, 2, status);
}
-MeasureUnit MeasureUnit::getGigabit() {
- return MeasureUnit(6, 2);
+MeasureUnit MeasureUnit::getGigabit() {
+ return MeasureUnit(6, 2);
}
MeasureUnit *MeasureUnit::createGigabyte(UErrorCode &status) {
- return MeasureUnit::create(6, 3, status);
-}
-
-MeasureUnit MeasureUnit::getGigabyte() {
- return MeasureUnit(6, 3);
+ return MeasureUnit::create(6, 3, status);
}
+MeasureUnit MeasureUnit::getGigabyte() {
+ return MeasureUnit(6, 3);
+}
+
MeasureUnit *MeasureUnit::createKilobit(UErrorCode &status) {
- return MeasureUnit::create(6, 4, status);
-}
-
-MeasureUnit MeasureUnit::getKilobit() {
- return MeasureUnit(6, 4);
+ return MeasureUnit::create(6, 4, status);
}
+MeasureUnit MeasureUnit::getKilobit() {
+ return MeasureUnit(6, 4);
+}
+
MeasureUnit *MeasureUnit::createKilobyte(UErrorCode &status) {
- return MeasureUnit::create(6, 5, status);
-}
-
-MeasureUnit MeasureUnit::getKilobyte() {
- return MeasureUnit(6, 5);
+ return MeasureUnit::create(6, 5, status);
}
+MeasureUnit MeasureUnit::getKilobyte() {
+ return MeasureUnit(6, 5);
+}
+
MeasureUnit *MeasureUnit::createMegabit(UErrorCode &status) {
- return MeasureUnit::create(6, 6, status);
-}
-
-MeasureUnit MeasureUnit::getMegabit() {
- return MeasureUnit(6, 6);
+ return MeasureUnit::create(6, 6, status);
}
+MeasureUnit MeasureUnit::getMegabit() {
+ return MeasureUnit(6, 6);
+}
+
MeasureUnit *MeasureUnit::createMegabyte(UErrorCode &status) {
- return MeasureUnit::create(6, 7, status);
-}
-
-MeasureUnit MeasureUnit::getMegabyte() {
- return MeasureUnit(6, 7);
-}
-
-MeasureUnit *MeasureUnit::createPetabyte(UErrorCode &status) {
- return MeasureUnit::create(6, 8, status);
-}
-
-MeasureUnit MeasureUnit::getPetabyte() {
- return MeasureUnit(6, 8);
-}
-
+ return MeasureUnit::create(6, 7, status);
+}
+
+MeasureUnit MeasureUnit::getMegabyte() {
+ return MeasureUnit(6, 7);
+}
+
+MeasureUnit *MeasureUnit::createPetabyte(UErrorCode &status) {
+ return MeasureUnit::create(6, 8, status);
+}
+
+MeasureUnit MeasureUnit::getPetabyte() {
+ return MeasureUnit(6, 8);
+}
+
MeasureUnit *MeasureUnit::createTerabit(UErrorCode &status) {
- return MeasureUnit::create(6, 9, status);
-}
-
-MeasureUnit MeasureUnit::getTerabit() {
- return MeasureUnit(6, 9);
+ return MeasureUnit::create(6, 9, status);
}
+MeasureUnit MeasureUnit::getTerabit() {
+ return MeasureUnit(6, 9);
+}
+
MeasureUnit *MeasureUnit::createTerabyte(UErrorCode &status) {
- return MeasureUnit::create(6, 10, status);
-}
-
-MeasureUnit MeasureUnit::getTerabyte() {
- return MeasureUnit(6, 10);
+ return MeasureUnit::create(6, 10, status);
}
+MeasureUnit MeasureUnit::getTerabyte() {
+ return MeasureUnit(6, 10);
+}
+
MeasureUnit *MeasureUnit::createCentury(UErrorCode &status) {
- return MeasureUnit::create(7, 0, status);
-}
-
-MeasureUnit MeasureUnit::getCentury() {
- return MeasureUnit(7, 0);
+ return MeasureUnit::create(7, 0, status);
}
+MeasureUnit MeasureUnit::getCentury() {
+ return MeasureUnit(7, 0);
+}
+
MeasureUnit *MeasureUnit::createDay(UErrorCode &status) {
- return MeasureUnit::create(7, 1, status);
-}
-
-MeasureUnit MeasureUnit::getDay() {
- return MeasureUnit(7, 1);
-}
-
-MeasureUnit *MeasureUnit::createDayPerson(UErrorCode &status) {
- return MeasureUnit::create(7, 2, status);
-}
-
-MeasureUnit MeasureUnit::getDayPerson() {
- return MeasureUnit(7, 2);
-}
-
-MeasureUnit *MeasureUnit::createDecade(UErrorCode &status) {
- return MeasureUnit::create(7, 3, status);
-}
-
-MeasureUnit MeasureUnit::getDecade() {
- return MeasureUnit(7, 3);
-}
-
+ return MeasureUnit::create(7, 1, status);
+}
+
+MeasureUnit MeasureUnit::getDay() {
+ return MeasureUnit(7, 1);
+}
+
+MeasureUnit *MeasureUnit::createDayPerson(UErrorCode &status) {
+ return MeasureUnit::create(7, 2, status);
+}
+
+MeasureUnit MeasureUnit::getDayPerson() {
+ return MeasureUnit(7, 2);
+}
+
+MeasureUnit *MeasureUnit::createDecade(UErrorCode &status) {
+ return MeasureUnit::create(7, 3, status);
+}
+
+MeasureUnit MeasureUnit::getDecade() {
+ return MeasureUnit(7, 3);
+}
+
MeasureUnit *MeasureUnit::createHour(UErrorCode &status) {
- return MeasureUnit::create(7, 4, status);
-}
-
-MeasureUnit MeasureUnit::getHour() {
- return MeasureUnit(7, 4);
+ return MeasureUnit::create(7, 4, status);
}
+MeasureUnit MeasureUnit::getHour() {
+ return MeasureUnit(7, 4);
+}
+
MeasureUnit *MeasureUnit::createMicrosecond(UErrorCode &status) {
- return MeasureUnit::create(7, 5, status);
-}
-
-MeasureUnit MeasureUnit::getMicrosecond() {
- return MeasureUnit(7, 5);
+ return MeasureUnit::create(7, 5, status);
}
+MeasureUnit MeasureUnit::getMicrosecond() {
+ return MeasureUnit(7, 5);
+}
+
MeasureUnit *MeasureUnit::createMillisecond(UErrorCode &status) {
- return MeasureUnit::create(7, 6, status);
-}
-
-MeasureUnit MeasureUnit::getMillisecond() {
- return MeasureUnit(7, 6);
+ return MeasureUnit::create(7, 6, status);
}
+MeasureUnit MeasureUnit::getMillisecond() {
+ return MeasureUnit(7, 6);
+}
+
MeasureUnit *MeasureUnit::createMinute(UErrorCode &status) {
- return MeasureUnit::create(7, 7, status);
-}
-
-MeasureUnit MeasureUnit::getMinute() {
- return MeasureUnit(7, 7);
+ return MeasureUnit::create(7, 7, status);
}
+MeasureUnit MeasureUnit::getMinute() {
+ return MeasureUnit(7, 7);
+}
+
MeasureUnit *MeasureUnit::createMonth(UErrorCode &status) {
- return MeasureUnit::create(7, 8, status);
-}
-
-MeasureUnit MeasureUnit::getMonth() {
- return MeasureUnit(7, 8);
-}
-
-MeasureUnit *MeasureUnit::createMonthPerson(UErrorCode &status) {
- return MeasureUnit::create(7, 9, status);
-}
-
-MeasureUnit MeasureUnit::getMonthPerson() {
- return MeasureUnit(7, 9);
-}
-
+ return MeasureUnit::create(7, 8, status);
+}
+
+MeasureUnit MeasureUnit::getMonth() {
+ return MeasureUnit(7, 8);
+}
+
+MeasureUnit *MeasureUnit::createMonthPerson(UErrorCode &status) {
+ return MeasureUnit::create(7, 9, status);
+}
+
+MeasureUnit MeasureUnit::getMonthPerson() {
+ return MeasureUnit(7, 9);
+}
+
MeasureUnit *MeasureUnit::createNanosecond(UErrorCode &status) {
- return MeasureUnit::create(7, 10, status);
-}
-
-MeasureUnit MeasureUnit::getNanosecond() {
- return MeasureUnit(7, 10);
+ return MeasureUnit::create(7, 10, status);
}
+MeasureUnit MeasureUnit::getNanosecond() {
+ return MeasureUnit(7, 10);
+}
+
MeasureUnit *MeasureUnit::createSecond(UErrorCode &status) {
- return MeasureUnit::create(7, 11, status);
-}
-
-MeasureUnit MeasureUnit::getSecond() {
- return MeasureUnit(7, 11);
+ return MeasureUnit::create(7, 11, status);
}
+MeasureUnit MeasureUnit::getSecond() {
+ return MeasureUnit(7, 11);
+}
+
MeasureUnit *MeasureUnit::createWeek(UErrorCode &status) {
- return MeasureUnit::create(7, 12, status);
-}
-
-MeasureUnit MeasureUnit::getWeek() {
- return MeasureUnit(7, 12);
-}
-
-MeasureUnit *MeasureUnit::createWeekPerson(UErrorCode &status) {
- return MeasureUnit::create(7, 13, status);
-}
-
-MeasureUnit MeasureUnit::getWeekPerson() {
- return MeasureUnit(7, 13);
-}
-
+ return MeasureUnit::create(7, 12, status);
+}
+
+MeasureUnit MeasureUnit::getWeek() {
+ return MeasureUnit(7, 12);
+}
+
+MeasureUnit *MeasureUnit::createWeekPerson(UErrorCode &status) {
+ return MeasureUnit::create(7, 13, status);
+}
+
+MeasureUnit MeasureUnit::getWeekPerson() {
+ return MeasureUnit(7, 13);
+}
+
MeasureUnit *MeasureUnit::createYear(UErrorCode &status) {
- return MeasureUnit::create(7, 14, status);
-}
-
-MeasureUnit MeasureUnit::getYear() {
- return MeasureUnit(7, 14);
-}
-
-MeasureUnit *MeasureUnit::createYearPerson(UErrorCode &status) {
- return MeasureUnit::create(7, 15, status);
-}
-
-MeasureUnit MeasureUnit::getYearPerson() {
- return MeasureUnit(7, 15);
-}
-
+ return MeasureUnit::create(7, 14, status);
+}
+
+MeasureUnit MeasureUnit::getYear() {
+ return MeasureUnit(7, 14);
+}
+
+MeasureUnit *MeasureUnit::createYearPerson(UErrorCode &status) {
+ return MeasureUnit::create(7, 15, status);
+}
+
+MeasureUnit MeasureUnit::getYearPerson() {
+ return MeasureUnit(7, 15);
+}
+
MeasureUnit *MeasureUnit::createAmpere(UErrorCode &status) {
- return MeasureUnit::create(8, 0, status);
-}
-
-MeasureUnit MeasureUnit::getAmpere() {
- return MeasureUnit(8, 0);
+ return MeasureUnit::create(8, 0, status);
}
+MeasureUnit MeasureUnit::getAmpere() {
+ return MeasureUnit(8, 0);
+}
+
MeasureUnit *MeasureUnit::createMilliampere(UErrorCode &status) {
- return MeasureUnit::create(8, 1, status);
-}
-
-MeasureUnit MeasureUnit::getMilliampere() {
- return MeasureUnit(8, 1);
+ return MeasureUnit::create(8, 1, status);
}
+MeasureUnit MeasureUnit::getMilliampere() {
+ return MeasureUnit(8, 1);
+}
+
MeasureUnit *MeasureUnit::createOhm(UErrorCode &status) {
- return MeasureUnit::create(8, 2, status);
-}
-
-MeasureUnit MeasureUnit::getOhm() {
- return MeasureUnit(8, 2);
+ return MeasureUnit::create(8, 2, status);
}
+MeasureUnit MeasureUnit::getOhm() {
+ return MeasureUnit(8, 2);
+}
+
MeasureUnit *MeasureUnit::createVolt(UErrorCode &status) {
- return MeasureUnit::create(8, 3, status);
-}
-
-MeasureUnit MeasureUnit::getVolt() {
- return MeasureUnit(8, 3);
-}
-
-MeasureUnit *MeasureUnit::createBritishThermalUnit(UErrorCode &status) {
- return MeasureUnit::create(9, 0, status);
-}
-
-MeasureUnit MeasureUnit::getBritishThermalUnit() {
- return MeasureUnit(9, 0);
-}
-
+ return MeasureUnit::create(8, 3, status);
+}
+
+MeasureUnit MeasureUnit::getVolt() {
+ return MeasureUnit(8, 3);
+}
+
+MeasureUnit *MeasureUnit::createBritishThermalUnit(UErrorCode &status) {
+ return MeasureUnit::create(9, 0, status);
+}
+
+MeasureUnit MeasureUnit::getBritishThermalUnit() {
+ return MeasureUnit(9, 0);
+}
+
MeasureUnit *MeasureUnit::createCalorie(UErrorCode &status) {
- return MeasureUnit::create(9, 1, status);
-}
-
-MeasureUnit MeasureUnit::getCalorie() {
- return MeasureUnit(9, 1);
-}
-
-MeasureUnit *MeasureUnit::createElectronvolt(UErrorCode &status) {
- return MeasureUnit::create(9, 2, status);
-}
-
-MeasureUnit MeasureUnit::getElectronvolt() {
- return MeasureUnit(9, 2);
-}
-
+ return MeasureUnit::create(9, 1, status);
+}
+
+MeasureUnit MeasureUnit::getCalorie() {
+ return MeasureUnit(9, 1);
+}
+
+MeasureUnit *MeasureUnit::createElectronvolt(UErrorCode &status) {
+ return MeasureUnit::create(9, 2, status);
+}
+
+MeasureUnit MeasureUnit::getElectronvolt() {
+ return MeasureUnit(9, 2);
+}
+
MeasureUnit *MeasureUnit::createFoodcalorie(UErrorCode &status) {
- return MeasureUnit::create(9, 3, status);
-}
-
-MeasureUnit MeasureUnit::getFoodcalorie() {
- return MeasureUnit(9, 3);
+ return MeasureUnit::create(9, 3, status);
}
+MeasureUnit MeasureUnit::getFoodcalorie() {
+ return MeasureUnit(9, 3);
+}
+
MeasureUnit *MeasureUnit::createJoule(UErrorCode &status) {
- return MeasureUnit::create(9, 4, status);
-}
-
-MeasureUnit MeasureUnit::getJoule() {
- return MeasureUnit(9, 4);
+ return MeasureUnit::create(9, 4, status);
}
+MeasureUnit MeasureUnit::getJoule() {
+ return MeasureUnit(9, 4);
+}
+
MeasureUnit *MeasureUnit::createKilocalorie(UErrorCode &status) {
- return MeasureUnit::create(9, 5, status);
-}
-
-MeasureUnit MeasureUnit::getKilocalorie() {
- return MeasureUnit(9, 5);
+ return MeasureUnit::create(9, 5, status);
}
+MeasureUnit MeasureUnit::getKilocalorie() {
+ return MeasureUnit(9, 5);
+}
+
MeasureUnit *MeasureUnit::createKilojoule(UErrorCode &status) {
- return MeasureUnit::create(9, 6, status);
-}
-
-MeasureUnit MeasureUnit::getKilojoule() {
- return MeasureUnit(9, 6);
+ return MeasureUnit::create(9, 6, status);
}
+MeasureUnit MeasureUnit::getKilojoule() {
+ return MeasureUnit(9, 6);
+}
+
MeasureUnit *MeasureUnit::createKilowattHour(UErrorCode &status) {
- return MeasureUnit::create(9, 7, status);
-}
-
-MeasureUnit MeasureUnit::getKilowattHour() {
- return MeasureUnit(9, 7);
-}
-
-MeasureUnit *MeasureUnit::createThermUs(UErrorCode &status) {
- return MeasureUnit::create(9, 8, status);
-}
-
-MeasureUnit MeasureUnit::getThermUs() {
- return MeasureUnit(9, 8);
-}
-
-MeasureUnit *MeasureUnit::createNewton(UErrorCode &status) {
- return MeasureUnit::create(10, 0, status);
-}
-
-MeasureUnit MeasureUnit::getNewton() {
- return MeasureUnit(10, 0);
-}
-
-MeasureUnit *MeasureUnit::createPoundForce(UErrorCode &status) {
- return MeasureUnit::create(10, 1, status);
-}
-
-MeasureUnit MeasureUnit::getPoundForce() {
- return MeasureUnit(10, 1);
-}
-
+ return MeasureUnit::create(9, 7, status);
+}
+
+MeasureUnit MeasureUnit::getKilowattHour() {
+ return MeasureUnit(9, 7);
+}
+
+MeasureUnit *MeasureUnit::createThermUs(UErrorCode &status) {
+ return MeasureUnit::create(9, 8, status);
+}
+
+MeasureUnit MeasureUnit::getThermUs() {
+ return MeasureUnit(9, 8);
+}
+
+MeasureUnit *MeasureUnit::createNewton(UErrorCode &status) {
+ return MeasureUnit::create(10, 0, status);
+}
+
+MeasureUnit MeasureUnit::getNewton() {
+ return MeasureUnit(10, 0);
+}
+
+MeasureUnit *MeasureUnit::createPoundForce(UErrorCode &status) {
+ return MeasureUnit::create(10, 1, status);
+}
+
+MeasureUnit MeasureUnit::getPoundForce() {
+ return MeasureUnit(10, 1);
+}
+
MeasureUnit *MeasureUnit::createGigahertz(UErrorCode &status) {
return MeasureUnit::create(11, 0, status);
}
-MeasureUnit MeasureUnit::getGigahertz() {
- return MeasureUnit(11, 0);
-}
-
+MeasureUnit MeasureUnit::getGigahertz() {
+ return MeasureUnit(11, 0);
+}
+
MeasureUnit *MeasureUnit::createHertz(UErrorCode &status) {
return MeasureUnit::create(11, 1, status);
}
-MeasureUnit MeasureUnit::getHertz() {
- return MeasureUnit(11, 1);
-}
-
+MeasureUnit MeasureUnit::getHertz() {
+ return MeasureUnit(11, 1);
+}
+
MeasureUnit *MeasureUnit::createKilohertz(UErrorCode &status) {
return MeasureUnit::create(11, 2, status);
}
-MeasureUnit MeasureUnit::getKilohertz() {
- return MeasureUnit(11, 2);
-}
-
+MeasureUnit MeasureUnit::getKilohertz() {
+ return MeasureUnit(11, 2);
+}
+
MeasureUnit *MeasureUnit::createMegahertz(UErrorCode &status) {
return MeasureUnit::create(11, 3, status);
}
-MeasureUnit MeasureUnit::getMegahertz() {
- return MeasureUnit(11, 3);
-}
-
-MeasureUnit *MeasureUnit::createDotPerCentimeter(UErrorCode &status) {
+MeasureUnit MeasureUnit::getMegahertz() {
+ return MeasureUnit(11, 3);
+}
+
+MeasureUnit *MeasureUnit::createDotPerCentimeter(UErrorCode &status) {
return MeasureUnit::create(12, 0, status);
}
-MeasureUnit MeasureUnit::getDotPerCentimeter() {
- return MeasureUnit(12, 0);
-}
-
-MeasureUnit *MeasureUnit::createDotPerInch(UErrorCode &status) {
+MeasureUnit MeasureUnit::getDotPerCentimeter() {
+ return MeasureUnit(12, 0);
+}
+
+MeasureUnit *MeasureUnit::createDotPerInch(UErrorCode &status) {
return MeasureUnit::create(12, 1, status);
}
-MeasureUnit MeasureUnit::getDotPerInch() {
- return MeasureUnit(12, 1);
-}
-
-MeasureUnit *MeasureUnit::createEm(UErrorCode &status) {
+MeasureUnit MeasureUnit::getDotPerInch() {
+ return MeasureUnit(12, 1);
+}
+
+MeasureUnit *MeasureUnit::createEm(UErrorCode &status) {
return MeasureUnit::create(12, 2, status);
}
-MeasureUnit MeasureUnit::getEm() {
- return MeasureUnit(12, 2);
-}
-
-MeasureUnit *MeasureUnit::createMegapixel(UErrorCode &status) {
+MeasureUnit MeasureUnit::getEm() {
+ return MeasureUnit(12, 2);
+}
+
+MeasureUnit *MeasureUnit::createMegapixel(UErrorCode &status) {
return MeasureUnit::create(12, 3, status);
}
-MeasureUnit MeasureUnit::getMegapixel() {
- return MeasureUnit(12, 3);
-}
-
-MeasureUnit *MeasureUnit::createPixel(UErrorCode &status) {
+MeasureUnit MeasureUnit::getMegapixel() {
+ return MeasureUnit(12, 3);
+}
+
+MeasureUnit *MeasureUnit::createPixel(UErrorCode &status) {
return MeasureUnit::create(12, 4, status);
}
-MeasureUnit MeasureUnit::getPixel() {
- return MeasureUnit(12, 4);
-}
-
-MeasureUnit *MeasureUnit::createPixelPerCentimeter(UErrorCode &status) {
+MeasureUnit MeasureUnit::getPixel() {
+ return MeasureUnit(12, 4);
+}
+
+MeasureUnit *MeasureUnit::createPixelPerCentimeter(UErrorCode &status) {
return MeasureUnit::create(12, 5, status);
}
-MeasureUnit MeasureUnit::getPixelPerCentimeter() {
- return MeasureUnit(12, 5);
-}
-
-MeasureUnit *MeasureUnit::createPixelPerInch(UErrorCode &status) {
+MeasureUnit MeasureUnit::getPixelPerCentimeter() {
+ return MeasureUnit(12, 5);
+}
+
+MeasureUnit *MeasureUnit::createPixelPerInch(UErrorCode &status) {
return MeasureUnit::create(12, 6, status);
}
-MeasureUnit MeasureUnit::getPixelPerInch() {
- return MeasureUnit(12, 6);
-}
-
-MeasureUnit *MeasureUnit::createAstronomicalUnit(UErrorCode &status) {
- return MeasureUnit::create(13, 0, status);
-}
-
-MeasureUnit MeasureUnit::getAstronomicalUnit() {
- return MeasureUnit(13, 0);
-}
-
-MeasureUnit *MeasureUnit::createCentimeter(UErrorCode &status) {
- return MeasureUnit::create(13, 1, status);
-}
-
-MeasureUnit MeasureUnit::getCentimeter() {
- return MeasureUnit(13, 1);
-}
-
-MeasureUnit *MeasureUnit::createDecimeter(UErrorCode &status) {
- return MeasureUnit::create(13, 2, status);
-}
-
-MeasureUnit MeasureUnit::getDecimeter() {
- return MeasureUnit(13, 2);
-}
-
-MeasureUnit *MeasureUnit::createFathom(UErrorCode &status) {
- return MeasureUnit::create(13, 3, status);
-}
-
-MeasureUnit MeasureUnit::getFathom() {
- return MeasureUnit(13, 3);
-}
-
-MeasureUnit *MeasureUnit::createFoot(UErrorCode &status) {
- return MeasureUnit::create(13, 4, status);
-}
-
-MeasureUnit MeasureUnit::getFoot() {
- return MeasureUnit(13, 4);
-}
-
-MeasureUnit *MeasureUnit::createFurlong(UErrorCode &status) {
- return MeasureUnit::create(13, 5, status);
-}
-
-MeasureUnit MeasureUnit::getFurlong() {
- return MeasureUnit(13, 5);
-}
-
-MeasureUnit *MeasureUnit::createInch(UErrorCode &status) {
- return MeasureUnit::create(13, 6, status);
-}
-
-MeasureUnit MeasureUnit::getInch() {
- return MeasureUnit(13, 6);
-}
-
+MeasureUnit MeasureUnit::getPixelPerInch() {
+ return MeasureUnit(12, 6);
+}
+
+MeasureUnit *MeasureUnit::createAstronomicalUnit(UErrorCode &status) {
+ return MeasureUnit::create(13, 0, status);
+}
+
+MeasureUnit MeasureUnit::getAstronomicalUnit() {
+ return MeasureUnit(13, 0);
+}
+
+MeasureUnit *MeasureUnit::createCentimeter(UErrorCode &status) {
+ return MeasureUnit::create(13, 1, status);
+}
+
+MeasureUnit MeasureUnit::getCentimeter() {
+ return MeasureUnit(13, 1);
+}
+
+MeasureUnit *MeasureUnit::createDecimeter(UErrorCode &status) {
+ return MeasureUnit::create(13, 2, status);
+}
+
+MeasureUnit MeasureUnit::getDecimeter() {
+ return MeasureUnit(13, 2);
+}
+
+MeasureUnit *MeasureUnit::createFathom(UErrorCode &status) {
+ return MeasureUnit::create(13, 3, status);
+}
+
+MeasureUnit MeasureUnit::getFathom() {
+ return MeasureUnit(13, 3);
+}
+
+MeasureUnit *MeasureUnit::createFoot(UErrorCode &status) {
+ return MeasureUnit::create(13, 4, status);
+}
+
+MeasureUnit MeasureUnit::getFoot() {
+ return MeasureUnit(13, 4);
+}
+
+MeasureUnit *MeasureUnit::createFurlong(UErrorCode &status) {
+ return MeasureUnit::create(13, 5, status);
+}
+
+MeasureUnit MeasureUnit::getFurlong() {
+ return MeasureUnit(13, 5);
+}
+
+MeasureUnit *MeasureUnit::createInch(UErrorCode &status) {
+ return MeasureUnit::create(13, 6, status);
+}
+
+MeasureUnit MeasureUnit::getInch() {
+ return MeasureUnit(13, 6);
+}
+
MeasureUnit *MeasureUnit::createKilometer(UErrorCode &status) {
- return MeasureUnit::create(13, 7, status);
-}
-
-MeasureUnit MeasureUnit::getKilometer() {
- return MeasureUnit(13, 7);
+ return MeasureUnit::create(13, 7, status);
}
+MeasureUnit MeasureUnit::getKilometer() {
+ return MeasureUnit(13, 7);
+}
+
MeasureUnit *MeasureUnit::createLightYear(UErrorCode &status) {
- return MeasureUnit::create(13, 8, status);
-}
-
-MeasureUnit MeasureUnit::getLightYear() {
- return MeasureUnit(13, 8);
+ return MeasureUnit::create(13, 8, status);
}
+MeasureUnit MeasureUnit::getLightYear() {
+ return MeasureUnit(13, 8);
+}
+
MeasureUnit *MeasureUnit::createMeter(UErrorCode &status) {
- return MeasureUnit::create(13, 9, status);
-}
-
-MeasureUnit MeasureUnit::getMeter() {
- return MeasureUnit(13, 9);
+ return MeasureUnit::create(13, 9, status);
}
+MeasureUnit MeasureUnit::getMeter() {
+ return MeasureUnit(13, 9);
+}
+
MeasureUnit *MeasureUnit::createMicrometer(UErrorCode &status) {
- return MeasureUnit::create(13, 10, status);
-}
-
-MeasureUnit MeasureUnit::getMicrometer() {
- return MeasureUnit(13, 10);
+ return MeasureUnit::create(13, 10, status);
}
+MeasureUnit MeasureUnit::getMicrometer() {
+ return MeasureUnit(13, 10);
+}
+
MeasureUnit *MeasureUnit::createMile(UErrorCode &status) {
- return MeasureUnit::create(13, 11, status);
-}
-
-MeasureUnit MeasureUnit::getMile() {
- return MeasureUnit(13, 11);
+ return MeasureUnit::create(13, 11, status);
}
+MeasureUnit MeasureUnit::getMile() {
+ return MeasureUnit(13, 11);
+}
+
MeasureUnit *MeasureUnit::createMileScandinavian(UErrorCode &status) {
- return MeasureUnit::create(13, 12, status);
-}
-
-MeasureUnit MeasureUnit::getMileScandinavian() {
- return MeasureUnit(13, 12);
+ return MeasureUnit::create(13, 12, status);
}
+MeasureUnit MeasureUnit::getMileScandinavian() {
+ return MeasureUnit(13, 12);
+}
+
MeasureUnit *MeasureUnit::createMillimeter(UErrorCode &status) {
- return MeasureUnit::create(13, 13, status);
-}
-
-MeasureUnit MeasureUnit::getMillimeter() {
- return MeasureUnit(13, 13);
+ return MeasureUnit::create(13, 13, status);
}
+MeasureUnit MeasureUnit::getMillimeter() {
+ return MeasureUnit(13, 13);
+}
+
MeasureUnit *MeasureUnit::createNanometer(UErrorCode &status) {
- return MeasureUnit::create(13, 14, status);
-}
-
-MeasureUnit MeasureUnit::getNanometer() {
- return MeasureUnit(13, 14);
+ return MeasureUnit::create(13, 14, status);
}
+MeasureUnit MeasureUnit::getNanometer() {
+ return MeasureUnit(13, 14);
+}
+
MeasureUnit *MeasureUnit::createNauticalMile(UErrorCode &status) {
- return MeasureUnit::create(13, 15, status);
-}
-
-MeasureUnit MeasureUnit::getNauticalMile() {
- return MeasureUnit(13, 15);
+ return MeasureUnit::create(13, 15, status);
}
+MeasureUnit MeasureUnit::getNauticalMile() {
+ return MeasureUnit(13, 15);
+}
+
MeasureUnit *MeasureUnit::createParsec(UErrorCode &status) {
- return MeasureUnit::create(13, 16, status);
-}
-
-MeasureUnit MeasureUnit::getParsec() {
- return MeasureUnit(13, 16);
+ return MeasureUnit::create(13, 16, status);
}
+MeasureUnit MeasureUnit::getParsec() {
+ return MeasureUnit(13, 16);
+}
+
MeasureUnit *MeasureUnit::createPicometer(UErrorCode &status) {
- return MeasureUnit::create(13, 17, status);
-}
-
-MeasureUnit MeasureUnit::getPicometer() {
- return MeasureUnit(13, 17);
-}
-
-MeasureUnit *MeasureUnit::createPoint(UErrorCode &status) {
- return MeasureUnit::create(13, 18, status);
-}
-
-MeasureUnit MeasureUnit::getPoint() {
- return MeasureUnit(13, 18);
-}
-
-MeasureUnit *MeasureUnit::createSolarRadius(UErrorCode &status) {
- return MeasureUnit::create(13, 19, status);
-}
-
-MeasureUnit MeasureUnit::getSolarRadius() {
- return MeasureUnit(13, 19);
-}
-
+ return MeasureUnit::create(13, 17, status);
+}
+
+MeasureUnit MeasureUnit::getPicometer() {
+ return MeasureUnit(13, 17);
+}
+
+MeasureUnit *MeasureUnit::createPoint(UErrorCode &status) {
+ return MeasureUnit::create(13, 18, status);
+}
+
+MeasureUnit MeasureUnit::getPoint() {
+ return MeasureUnit(13, 18);
+}
+
+MeasureUnit *MeasureUnit::createSolarRadius(UErrorCode &status) {
+ return MeasureUnit::create(13, 19, status);
+}
+
+MeasureUnit MeasureUnit::getSolarRadius() {
+ return MeasureUnit(13, 19);
+}
+
MeasureUnit *MeasureUnit::createYard(UErrorCode &status) {
- return MeasureUnit::create(13, 20, status);
-}
-
-MeasureUnit MeasureUnit::getYard() {
- return MeasureUnit(13, 20);
+ return MeasureUnit::create(13, 20, status);
}
+MeasureUnit MeasureUnit::getYard() {
+ return MeasureUnit(13, 20);
+}
+
MeasureUnit *MeasureUnit::createLux(UErrorCode &status) {
- return MeasureUnit::create(14, 0, status);
-}
-
-MeasureUnit MeasureUnit::getLux() {
- return MeasureUnit(14, 0);
-}
-
-MeasureUnit *MeasureUnit::createSolarLuminosity(UErrorCode &status) {
- return MeasureUnit::create(14, 1, status);
-}
-
-MeasureUnit MeasureUnit::getSolarLuminosity() {
- return MeasureUnit(14, 1);
-}
-
+ return MeasureUnit::create(14, 0, status);
+}
+
+MeasureUnit MeasureUnit::getLux() {
+ return MeasureUnit(14, 0);
+}
+
+MeasureUnit *MeasureUnit::createSolarLuminosity(UErrorCode &status) {
+ return MeasureUnit::create(14, 1, status);
+}
+
+MeasureUnit MeasureUnit::getSolarLuminosity() {
+ return MeasureUnit(14, 1);
+}
+
MeasureUnit *MeasureUnit::createCarat(UErrorCode &status) {
- return MeasureUnit::create(15, 0, status);
-}
-
-MeasureUnit MeasureUnit::getCarat() {
- return MeasureUnit(15, 0);
-}
-
-MeasureUnit *MeasureUnit::createDalton(UErrorCode &status) {
- return MeasureUnit::create(15, 1, status);
-}
-
-MeasureUnit MeasureUnit::getDalton() {
- return MeasureUnit(15, 1);
-}
-
-MeasureUnit *MeasureUnit::createEarthMass(UErrorCode &status) {
- return MeasureUnit::create(15, 2, status);
-}
-
-MeasureUnit MeasureUnit::getEarthMass() {
- return MeasureUnit(15, 2);
-}
-
+ return MeasureUnit::create(15, 0, status);
+}
+
+MeasureUnit MeasureUnit::getCarat() {
+ return MeasureUnit(15, 0);
+}
+
+MeasureUnit *MeasureUnit::createDalton(UErrorCode &status) {
+ return MeasureUnit::create(15, 1, status);
+}
+
+MeasureUnit MeasureUnit::getDalton() {
+ return MeasureUnit(15, 1);
+}
+
+MeasureUnit *MeasureUnit::createEarthMass(UErrorCode &status) {
+ return MeasureUnit::create(15, 2, status);
+}
+
+MeasureUnit MeasureUnit::getEarthMass() {
+ return MeasureUnit(15, 2);
+}
+
MeasureUnit *MeasureUnit::createGram(UErrorCode &status) {
- return MeasureUnit::create(15, 3, status);
-}
-
-MeasureUnit MeasureUnit::getGram() {
- return MeasureUnit(15, 3);
+ return MeasureUnit::create(15, 3, status);
}
+MeasureUnit MeasureUnit::getGram() {
+ return MeasureUnit(15, 3);
+}
+
MeasureUnit *MeasureUnit::createKilogram(UErrorCode &status) {
- return MeasureUnit::create(15, 4, status);
-}
-
-MeasureUnit MeasureUnit::getKilogram() {
- return MeasureUnit(15, 4);
+ return MeasureUnit::create(15, 4, status);
}
+MeasureUnit MeasureUnit::getKilogram() {
+ return MeasureUnit(15, 4);
+}
+
MeasureUnit *MeasureUnit::createMetricTon(UErrorCode &status) {
- return MeasureUnit::create(15, 5, status);
-}
-
-MeasureUnit MeasureUnit::getMetricTon() {
- return MeasureUnit(15, 5);
+ return MeasureUnit::create(15, 5, status);
}
+MeasureUnit MeasureUnit::getMetricTon() {
+ return MeasureUnit(15, 5);
+}
+
MeasureUnit *MeasureUnit::createMicrogram(UErrorCode &status) {
- return MeasureUnit::create(15, 6, status);
-}
-
-MeasureUnit MeasureUnit::getMicrogram() {
- return MeasureUnit(15, 6);
+ return MeasureUnit::create(15, 6, status);
}
+MeasureUnit MeasureUnit::getMicrogram() {
+ return MeasureUnit(15, 6);
+}
+
MeasureUnit *MeasureUnit::createMilligram(UErrorCode &status) {
- return MeasureUnit::create(15, 7, status);
-}
-
-MeasureUnit MeasureUnit::getMilligram() {
- return MeasureUnit(15, 7);
+ return MeasureUnit::create(15, 7, status);
}
+MeasureUnit MeasureUnit::getMilligram() {
+ return MeasureUnit(15, 7);
+}
+
MeasureUnit *MeasureUnit::createOunce(UErrorCode &status) {
- return MeasureUnit::create(15, 8, status);
-}
-
-MeasureUnit MeasureUnit::getOunce() {
- return MeasureUnit(15, 8);
+ return MeasureUnit::create(15, 8, status);
}
+MeasureUnit MeasureUnit::getOunce() {
+ return MeasureUnit(15, 8);
+}
+
MeasureUnit *MeasureUnit::createOunceTroy(UErrorCode &status) {
- return MeasureUnit::create(15, 9, status);
-}
-
-MeasureUnit MeasureUnit::getOunceTroy() {
- return MeasureUnit(15, 9);
+ return MeasureUnit::create(15, 9, status);
}
+MeasureUnit MeasureUnit::getOunceTroy() {
+ return MeasureUnit(15, 9);
+}
+
MeasureUnit *MeasureUnit::createPound(UErrorCode &status) {
- return MeasureUnit::create(15, 10, status);
-}
-
-MeasureUnit MeasureUnit::getPound() {
- return MeasureUnit(15, 10);
-}
-
-MeasureUnit *MeasureUnit::createSolarMass(UErrorCode &status) {
- return MeasureUnit::create(15, 11, status);
-}
-
-MeasureUnit MeasureUnit::getSolarMass() {
- return MeasureUnit(15, 11);
-}
-
+ return MeasureUnit::create(15, 10, status);
+}
+
+MeasureUnit MeasureUnit::getPound() {
+ return MeasureUnit(15, 10);
+}
+
+MeasureUnit *MeasureUnit::createSolarMass(UErrorCode &status) {
+ return MeasureUnit::create(15, 11, status);
+}
+
+MeasureUnit MeasureUnit::getSolarMass() {
+ return MeasureUnit(15, 11);
+}
+
MeasureUnit *MeasureUnit::createStone(UErrorCode &status) {
- return MeasureUnit::create(15, 12, status);
-}
-
-MeasureUnit MeasureUnit::getStone() {
- return MeasureUnit(15, 12);
+ return MeasureUnit::create(15, 12, status);
}
+MeasureUnit MeasureUnit::getStone() {
+ return MeasureUnit(15, 12);
+}
+
MeasureUnit *MeasureUnit::createTon(UErrorCode &status) {
- return MeasureUnit::create(15, 13, status);
-}
-
-MeasureUnit MeasureUnit::getTon() {
- return MeasureUnit(15, 13);
+ return MeasureUnit::create(15, 13, status);
}
+MeasureUnit MeasureUnit::getTon() {
+ return MeasureUnit(15, 13);
+}
+
MeasureUnit *MeasureUnit::createGigawatt(UErrorCode &status) {
- return MeasureUnit::create(17, 0, status);
-}
-
-MeasureUnit MeasureUnit::getGigawatt() {
- return MeasureUnit(17, 0);
+ return MeasureUnit::create(17, 0, status);
}
+MeasureUnit MeasureUnit::getGigawatt() {
+ return MeasureUnit(17, 0);
+}
+
MeasureUnit *MeasureUnit::createHorsepower(UErrorCode &status) {
- return MeasureUnit::create(17, 1, status);
-}
-
-MeasureUnit MeasureUnit::getHorsepower() {
- return MeasureUnit(17, 1);
+ return MeasureUnit::create(17, 1, status);
}
+MeasureUnit MeasureUnit::getHorsepower() {
+ return MeasureUnit(17, 1);
+}
+
MeasureUnit *MeasureUnit::createKilowatt(UErrorCode &status) {
- return MeasureUnit::create(17, 2, status);
-}
-
-MeasureUnit MeasureUnit::getKilowatt() {
- return MeasureUnit(17, 2);
+ return MeasureUnit::create(17, 2, status);
}
+MeasureUnit MeasureUnit::getKilowatt() {
+ return MeasureUnit(17, 2);
+}
+
MeasureUnit *MeasureUnit::createMegawatt(UErrorCode &status) {
- return MeasureUnit::create(17, 3, status);
-}
-
-MeasureUnit MeasureUnit::getMegawatt() {
- return MeasureUnit(17, 3);
+ return MeasureUnit::create(17, 3, status);
}
+MeasureUnit MeasureUnit::getMegawatt() {
+ return MeasureUnit(17, 3);
+}
+
MeasureUnit *MeasureUnit::createMilliwatt(UErrorCode &status) {
- return MeasureUnit::create(17, 4, status);
-}
-
-MeasureUnit MeasureUnit::getMilliwatt() {
- return MeasureUnit(17, 4);
+ return MeasureUnit::create(17, 4, status);
}
+MeasureUnit MeasureUnit::getMilliwatt() {
+ return MeasureUnit(17, 4);
+}
+
MeasureUnit *MeasureUnit::createWatt(UErrorCode &status) {
- return MeasureUnit::create(17, 5, status);
-}
-
-MeasureUnit MeasureUnit::getWatt() {
- return MeasureUnit(17, 5);
-}
-
-MeasureUnit *MeasureUnit::createAtmosphere(UErrorCode &status) {
- return MeasureUnit::create(18, 0, status);
-}
-
-MeasureUnit MeasureUnit::getAtmosphere() {
- return MeasureUnit(18, 0);
-}
-
-MeasureUnit *MeasureUnit::createBar(UErrorCode &status) {
- return MeasureUnit::create(18, 1, status);
-}
-
-MeasureUnit MeasureUnit::getBar() {
- return MeasureUnit(18, 1);
-}
-
+ return MeasureUnit::create(17, 5, status);
+}
+
+MeasureUnit MeasureUnit::getWatt() {
+ return MeasureUnit(17, 5);
+}
+
+MeasureUnit *MeasureUnit::createAtmosphere(UErrorCode &status) {
+ return MeasureUnit::create(18, 0, status);
+}
+
+MeasureUnit MeasureUnit::getAtmosphere() {
+ return MeasureUnit(18, 0);
+}
+
+MeasureUnit *MeasureUnit::createBar(UErrorCode &status) {
+ return MeasureUnit::create(18, 1, status);
+}
+
+MeasureUnit MeasureUnit::getBar() {
+ return MeasureUnit(18, 1);
+}
+
MeasureUnit *MeasureUnit::createHectopascal(UErrorCode &status) {
- return MeasureUnit::create(18, 2, status);
-}
-
-MeasureUnit MeasureUnit::getHectopascal() {
- return MeasureUnit(18, 2);
+ return MeasureUnit::create(18, 2, status);
}
+MeasureUnit MeasureUnit::getHectopascal() {
+ return MeasureUnit(18, 2);
+}
+
MeasureUnit *MeasureUnit::createInchHg(UErrorCode &status) {
- return MeasureUnit::create(18, 3, status);
-}
-
-MeasureUnit MeasureUnit::getInchHg() {
- return MeasureUnit(18, 3);
-}
-
-MeasureUnit *MeasureUnit::createKilopascal(UErrorCode &status) {
- return MeasureUnit::create(18, 4, status);
-}
-
-MeasureUnit MeasureUnit::getKilopascal() {
- return MeasureUnit(18, 4);
-}
-
-MeasureUnit *MeasureUnit::createMegapascal(UErrorCode &status) {
- return MeasureUnit::create(18, 5, status);
-}
-
-MeasureUnit MeasureUnit::getMegapascal() {
- return MeasureUnit(18, 5);
-}
-
+ return MeasureUnit::create(18, 3, status);
+}
+
+MeasureUnit MeasureUnit::getInchHg() {
+ return MeasureUnit(18, 3);
+}
+
+MeasureUnit *MeasureUnit::createKilopascal(UErrorCode &status) {
+ return MeasureUnit::create(18, 4, status);
+}
+
+MeasureUnit MeasureUnit::getKilopascal() {
+ return MeasureUnit(18, 4);
+}
+
+MeasureUnit *MeasureUnit::createMegapascal(UErrorCode &status) {
+ return MeasureUnit::create(18, 5, status);
+}
+
+MeasureUnit MeasureUnit::getMegapascal() {
+ return MeasureUnit(18, 5);
+}
+
MeasureUnit *MeasureUnit::createMillibar(UErrorCode &status) {
- return MeasureUnit::create(18, 6, status);
-}
-
-MeasureUnit MeasureUnit::getMillibar() {
- return MeasureUnit(18, 6);
+ return MeasureUnit::create(18, 6, status);
}
+MeasureUnit MeasureUnit::getMillibar() {
+ return MeasureUnit(18, 6);
+}
+
MeasureUnit *MeasureUnit::createMillimeterOfMercury(UErrorCode &status) {
- return MeasureUnit::create(18, 7, status);
-}
-
-MeasureUnit MeasureUnit::getMillimeterOfMercury() {
- return MeasureUnit(18, 7);
-}
-
-MeasureUnit *MeasureUnit::createPascal(UErrorCode &status) {
- return MeasureUnit::create(18, 8, status);
-}
-
-MeasureUnit MeasureUnit::getPascal() {
- return MeasureUnit(18, 8);
-}
-
+ return MeasureUnit::create(18, 7, status);
+}
+
+MeasureUnit MeasureUnit::getMillimeterOfMercury() {
+ return MeasureUnit(18, 7);
+}
+
+MeasureUnit *MeasureUnit::createPascal(UErrorCode &status) {
+ return MeasureUnit::create(18, 8, status);
+}
+
+MeasureUnit MeasureUnit::getPascal() {
+ return MeasureUnit(18, 8);
+}
+
MeasureUnit *MeasureUnit::createPoundPerSquareInch(UErrorCode &status) {
- return MeasureUnit::create(18, 9, status);
-}
-
-MeasureUnit MeasureUnit::getPoundPerSquareInch() {
- return MeasureUnit(18, 9);
+ return MeasureUnit::create(18, 9, status);
}
+MeasureUnit MeasureUnit::getPoundPerSquareInch() {
+ return MeasureUnit(18, 9);
+}
+
MeasureUnit *MeasureUnit::createKilometerPerHour(UErrorCode &status) {
- return MeasureUnit::create(19, 0, status);
-}
-
-MeasureUnit MeasureUnit::getKilometerPerHour() {
- return MeasureUnit(19, 0);
+ return MeasureUnit::create(19, 0, status);
}
+MeasureUnit MeasureUnit::getKilometerPerHour() {
+ return MeasureUnit(19, 0);
+}
+
MeasureUnit *MeasureUnit::createKnot(UErrorCode &status) {
- return MeasureUnit::create(19, 1, status);
-}
-
-MeasureUnit MeasureUnit::getKnot() {
- return MeasureUnit(19, 1);
+ return MeasureUnit::create(19, 1, status);
}
+MeasureUnit MeasureUnit::getKnot() {
+ return MeasureUnit(19, 1);
+}
+
MeasureUnit *MeasureUnit::createMeterPerSecond(UErrorCode &status) {
- return MeasureUnit::create(19, 2, status);
-}
-
-MeasureUnit MeasureUnit::getMeterPerSecond() {
- return MeasureUnit(19, 2);
+ return MeasureUnit::create(19, 2, status);
}
+MeasureUnit MeasureUnit::getMeterPerSecond() {
+ return MeasureUnit(19, 2);
+}
+
MeasureUnit *MeasureUnit::createMilePerHour(UErrorCode &status) {
- return MeasureUnit::create(19, 3, status);
-}
-
-MeasureUnit MeasureUnit::getMilePerHour() {
- return MeasureUnit(19, 3);
+ return MeasureUnit::create(19, 3, status);
}
+MeasureUnit MeasureUnit::getMilePerHour() {
+ return MeasureUnit(19, 3);
+}
+
MeasureUnit *MeasureUnit::createCelsius(UErrorCode &status) {
- return MeasureUnit::create(20, 0, status);
-}
-
-MeasureUnit MeasureUnit::getCelsius() {
- return MeasureUnit(20, 0);
+ return MeasureUnit::create(20, 0, status);
}
+MeasureUnit MeasureUnit::getCelsius() {
+ return MeasureUnit(20, 0);
+}
+
MeasureUnit *MeasureUnit::createFahrenheit(UErrorCode &status) {
- return MeasureUnit::create(20, 1, status);
-}
-
-MeasureUnit MeasureUnit::getFahrenheit() {
- return MeasureUnit(20, 1);
+ return MeasureUnit::create(20, 1, status);
}
+MeasureUnit MeasureUnit::getFahrenheit() {
+ return MeasureUnit(20, 1);
+}
+
MeasureUnit *MeasureUnit::createGenericTemperature(UErrorCode &status) {
- return MeasureUnit::create(20, 2, status);
-}
-
-MeasureUnit MeasureUnit::getGenericTemperature() {
- return MeasureUnit(20, 2);
+ return MeasureUnit::create(20, 2, status);
}
+MeasureUnit MeasureUnit::getGenericTemperature() {
+ return MeasureUnit(20, 2);
+}
+
MeasureUnit *MeasureUnit::createKelvin(UErrorCode &status) {
- return MeasureUnit::create(20, 3, status);
-}
-
-MeasureUnit MeasureUnit::getKelvin() {
- return MeasureUnit(20, 3);
-}
-
-MeasureUnit *MeasureUnit::createNewtonMeter(UErrorCode &status) {
- return MeasureUnit::create(21, 0, status);
-}
-
-MeasureUnit MeasureUnit::getNewtonMeter() {
- return MeasureUnit(21, 0);
-}
-
-MeasureUnit *MeasureUnit::createPoundFoot(UErrorCode &status) {
- return MeasureUnit::create(21, 1, status);
-}
-
-MeasureUnit MeasureUnit::getPoundFoot() {
- return MeasureUnit(21, 1);
-}
-
+ return MeasureUnit::create(20, 3, status);
+}
+
+MeasureUnit MeasureUnit::getKelvin() {
+ return MeasureUnit(20, 3);
+}
+
+MeasureUnit *MeasureUnit::createNewtonMeter(UErrorCode &status) {
+ return MeasureUnit::create(21, 0, status);
+}
+
+MeasureUnit MeasureUnit::getNewtonMeter() {
+ return MeasureUnit(21, 0);
+}
+
+MeasureUnit *MeasureUnit::createPoundFoot(UErrorCode &status) {
+ return MeasureUnit::create(21, 1, status);
+}
+
+MeasureUnit MeasureUnit::getPoundFoot() {
+ return MeasureUnit(21, 1);
+}
+
MeasureUnit *MeasureUnit::createAcreFoot(UErrorCode &status) {
- return MeasureUnit::create(22, 0, status);
-}
-
-MeasureUnit MeasureUnit::getAcreFoot() {
- return MeasureUnit(22, 0);
-}
-
-MeasureUnit *MeasureUnit::createBarrel(UErrorCode &status) {
- return MeasureUnit::create(22, 1, status);
-}
-
-MeasureUnit MeasureUnit::getBarrel() {
- return MeasureUnit(22, 1);
-}
-
+ return MeasureUnit::create(22, 0, status);
+}
+
+MeasureUnit MeasureUnit::getAcreFoot() {
+ return MeasureUnit(22, 0);
+}
+
+MeasureUnit *MeasureUnit::createBarrel(UErrorCode &status) {
+ return MeasureUnit::create(22, 1, status);
+}
+
+MeasureUnit MeasureUnit::getBarrel() {
+ return MeasureUnit(22, 1);
+}
+
MeasureUnit *MeasureUnit::createBushel(UErrorCode &status) {
- return MeasureUnit::create(22, 2, status);
-}
-
-MeasureUnit MeasureUnit::getBushel() {
- return MeasureUnit(22, 2);
+ return MeasureUnit::create(22, 2, status);
}
+MeasureUnit MeasureUnit::getBushel() {
+ return MeasureUnit(22, 2);
+}
+
MeasureUnit *MeasureUnit::createCentiliter(UErrorCode &status) {
- return MeasureUnit::create(22, 3, status);
-}
-
-MeasureUnit MeasureUnit::getCentiliter() {
- return MeasureUnit(22, 3);
+ return MeasureUnit::create(22, 3, status);
}
+MeasureUnit MeasureUnit::getCentiliter() {
+ return MeasureUnit(22, 3);
+}
+
MeasureUnit *MeasureUnit::createCubicCentimeter(UErrorCode &status) {
- return MeasureUnit::create(22, 4, status);
-}
-
-MeasureUnit MeasureUnit::getCubicCentimeter() {
- return MeasureUnit(22, 4);
+ return MeasureUnit::create(22, 4, status);
}
+MeasureUnit MeasureUnit::getCubicCentimeter() {
+ return MeasureUnit(22, 4);
+}
+
MeasureUnit *MeasureUnit::createCubicFoot(UErrorCode &status) {
- return MeasureUnit::create(22, 5, status);
-}
-
-MeasureUnit MeasureUnit::getCubicFoot() {
- return MeasureUnit(22, 5);
+ return MeasureUnit::create(22, 5, status);
}
+MeasureUnit MeasureUnit::getCubicFoot() {
+ return MeasureUnit(22, 5);
+}
+
MeasureUnit *MeasureUnit::createCubicInch(UErrorCode &status) {
- return MeasureUnit::create(22, 6, status);
-}
-
-MeasureUnit MeasureUnit::getCubicInch() {
- return MeasureUnit(22, 6);
+ return MeasureUnit::create(22, 6, status);
}
+MeasureUnit MeasureUnit::getCubicInch() {
+ return MeasureUnit(22, 6);
+}
+
MeasureUnit *MeasureUnit::createCubicKilometer(UErrorCode &status) {
- return MeasureUnit::create(22, 7, status);
-}
-
-MeasureUnit MeasureUnit::getCubicKilometer() {
- return MeasureUnit(22, 7);
+ return MeasureUnit::create(22, 7, status);
}
+MeasureUnit MeasureUnit::getCubicKilometer() {
+ return MeasureUnit(22, 7);
+}
+
MeasureUnit *MeasureUnit::createCubicMeter(UErrorCode &status) {
- return MeasureUnit::create(22, 8, status);
-}
-
-MeasureUnit MeasureUnit::getCubicMeter() {
- return MeasureUnit(22, 8);
+ return MeasureUnit::create(22, 8, status);
}
+MeasureUnit MeasureUnit::getCubicMeter() {
+ return MeasureUnit(22, 8);
+}
+
MeasureUnit *MeasureUnit::createCubicMile(UErrorCode &status) {
- return MeasureUnit::create(22, 9, status);
-}
-
-MeasureUnit MeasureUnit::getCubicMile() {
- return MeasureUnit(22, 9);
+ return MeasureUnit::create(22, 9, status);
}
+MeasureUnit MeasureUnit::getCubicMile() {
+ return MeasureUnit(22, 9);
+}
+
MeasureUnit *MeasureUnit::createCubicYard(UErrorCode &status) {
- return MeasureUnit::create(22, 10, status);
-}
-
-MeasureUnit MeasureUnit::getCubicYard() {
- return MeasureUnit(22, 10);
+ return MeasureUnit::create(22, 10, status);
}
+MeasureUnit MeasureUnit::getCubicYard() {
+ return MeasureUnit(22, 10);
+}
+
MeasureUnit *MeasureUnit::createCup(UErrorCode &status) {
- return MeasureUnit::create(22, 11, status);
-}
-
-MeasureUnit MeasureUnit::getCup() {
- return MeasureUnit(22, 11);
+ return MeasureUnit::create(22, 11, status);
}
+MeasureUnit MeasureUnit::getCup() {
+ return MeasureUnit(22, 11);
+}
+
MeasureUnit *MeasureUnit::createCupMetric(UErrorCode &status) {
- return MeasureUnit::create(22, 12, status);
-}
-
-MeasureUnit MeasureUnit::getCupMetric() {
- return MeasureUnit(22, 12);
+ return MeasureUnit::create(22, 12, status);
}
+MeasureUnit MeasureUnit::getCupMetric() {
+ return MeasureUnit(22, 12);
+}
+
MeasureUnit *MeasureUnit::createDeciliter(UErrorCode &status) {
- return MeasureUnit::create(22, 13, status);
-}
-
-MeasureUnit MeasureUnit::getDeciliter() {
- return MeasureUnit(22, 13);
+ return MeasureUnit::create(22, 13, status);
}
+MeasureUnit MeasureUnit::getDeciliter() {
+ return MeasureUnit(22, 13);
+}
+
MeasureUnit *MeasureUnit::createFluidOunce(UErrorCode &status) {
- return MeasureUnit::create(22, 14, status);
-}
-
-MeasureUnit MeasureUnit::getFluidOunce() {
- return MeasureUnit(22, 14);
-}
-
-MeasureUnit *MeasureUnit::createFluidOunceImperial(UErrorCode &status) {
- return MeasureUnit::create(22, 15, status);
-}
-
-MeasureUnit MeasureUnit::getFluidOunceImperial() {
- return MeasureUnit(22, 15);
-}
-
+ return MeasureUnit::create(22, 14, status);
+}
+
+MeasureUnit MeasureUnit::getFluidOunce() {
+ return MeasureUnit(22, 14);
+}
+
+MeasureUnit *MeasureUnit::createFluidOunceImperial(UErrorCode &status) {
+ return MeasureUnit::create(22, 15, status);
+}
+
+MeasureUnit MeasureUnit::getFluidOunceImperial() {
+ return MeasureUnit(22, 15);
+}
+
MeasureUnit *MeasureUnit::createGallon(UErrorCode &status) {
- return MeasureUnit::create(22, 16, status);
-}
-
-MeasureUnit MeasureUnit::getGallon() {
- return MeasureUnit(22, 16);
+ return MeasureUnit::create(22, 16, status);
}
+MeasureUnit MeasureUnit::getGallon() {
+ return MeasureUnit(22, 16);
+}
+
MeasureUnit *MeasureUnit::createGallonImperial(UErrorCode &status) {
- return MeasureUnit::create(22, 17, status);
-}
-
-MeasureUnit MeasureUnit::getGallonImperial() {
- return MeasureUnit(22, 17);
+ return MeasureUnit::create(22, 17, status);
}
+MeasureUnit MeasureUnit::getGallonImperial() {
+ return MeasureUnit(22, 17);
+}
+
MeasureUnit *MeasureUnit::createHectoliter(UErrorCode &status) {
- return MeasureUnit::create(22, 18, status);
-}
-
-MeasureUnit MeasureUnit::getHectoliter() {
- return MeasureUnit(22, 18);
+ return MeasureUnit::create(22, 18, status);
}
+MeasureUnit MeasureUnit::getHectoliter() {
+ return MeasureUnit(22, 18);
+}
+
MeasureUnit *MeasureUnit::createLiter(UErrorCode &status) {
- return MeasureUnit::create(22, 19, status);
-}
-
-MeasureUnit MeasureUnit::getLiter() {
- return MeasureUnit(22, 19);
+ return MeasureUnit::create(22, 19, status);
}
+MeasureUnit MeasureUnit::getLiter() {
+ return MeasureUnit(22, 19);
+}
+
MeasureUnit *MeasureUnit::createMegaliter(UErrorCode &status) {
- return MeasureUnit::create(22, 20, status);
-}
-
-MeasureUnit MeasureUnit::getMegaliter() {
- return MeasureUnit(22, 20);
+ return MeasureUnit::create(22, 20, status);
}
+MeasureUnit MeasureUnit::getMegaliter() {
+ return MeasureUnit(22, 20);
+}
+
MeasureUnit *MeasureUnit::createMilliliter(UErrorCode &status) {
- return MeasureUnit::create(22, 21, status);
-}
-
-MeasureUnit MeasureUnit::getMilliliter() {
- return MeasureUnit(22, 21);
+ return MeasureUnit::create(22, 21, status);
}
+MeasureUnit MeasureUnit::getMilliliter() {
+ return MeasureUnit(22, 21);
+}
+
MeasureUnit *MeasureUnit::createPint(UErrorCode &status) {
- return MeasureUnit::create(22, 22, status);
-}
-
-MeasureUnit MeasureUnit::getPint() {
- return MeasureUnit(22, 22);
+ return MeasureUnit::create(22, 22, status);
}
+MeasureUnit MeasureUnit::getPint() {
+ return MeasureUnit(22, 22);
+}
+
MeasureUnit *MeasureUnit::createPintMetric(UErrorCode &status) {
- return MeasureUnit::create(22, 23, status);
-}
-
-MeasureUnit MeasureUnit::getPintMetric() {
- return MeasureUnit(22, 23);
+ return MeasureUnit::create(22, 23, status);
}
+MeasureUnit MeasureUnit::getPintMetric() {
+ return MeasureUnit(22, 23);
+}
+
MeasureUnit *MeasureUnit::createQuart(UErrorCode &status) {
- return MeasureUnit::create(22, 24, status);
-}
-
-MeasureUnit MeasureUnit::getQuart() {
- return MeasureUnit(22, 24);
+ return MeasureUnit::create(22, 24, status);
}
+MeasureUnit MeasureUnit::getQuart() {
+ return MeasureUnit(22, 24);
+}
+
MeasureUnit *MeasureUnit::createTablespoon(UErrorCode &status) {
- return MeasureUnit::create(22, 25, status);
-}
-
-MeasureUnit MeasureUnit::getTablespoon() {
- return MeasureUnit(22, 25);
+ return MeasureUnit::create(22, 25, status);
}
+MeasureUnit MeasureUnit::getTablespoon() {
+ return MeasureUnit(22, 25);
+}
+
MeasureUnit *MeasureUnit::createTeaspoon(UErrorCode &status) {
- return MeasureUnit::create(22, 26, status);
-}
-
-MeasureUnit MeasureUnit::getTeaspoon() {
- return MeasureUnit(22, 26);
+ return MeasureUnit::create(22, 26, status);
}
+MeasureUnit MeasureUnit::getTeaspoon() {
+ return MeasureUnit(22, 26);
+}
+
// End generated code
static int32_t binarySearch(
- const char * const * array, int32_t start, int32_t end, StringPiece key) {
+ const char * const * array, int32_t start, int32_t end, StringPiece key) {
while (start < end) {
int32_t mid = (start + end) / 2;
- int32_t cmp = StringPiece(array[mid]).compare(key);
+ int32_t cmp = StringPiece(array[mid]).compare(key);
if (cmp < 0) {
start = mid + 1;
continue;
@@ -2007,95 +2007,95 @@ static int32_t binarySearch(
}
return -1;
}
-
-MeasureUnit::MeasureUnit() : MeasureUnit(kBaseTypeIdx, kBaseSubTypeIdx) {
-}
-
-MeasureUnit::MeasureUnit(int32_t typeId, int32_t subTypeId)
- : fImpl(nullptr), fSubTypeId(subTypeId), fTypeId(typeId) {
-}
-
+
+MeasureUnit::MeasureUnit() : MeasureUnit(kBaseTypeIdx, kBaseSubTypeIdx) {
+}
+
+MeasureUnit::MeasureUnit(int32_t typeId, int32_t subTypeId)
+ : fImpl(nullptr), fSubTypeId(subTypeId), fTypeId(typeId) {
+}
+
MeasureUnit::MeasureUnit(const MeasureUnit &other)
- : fImpl(nullptr) {
- *this = other;
-}
-
-MeasureUnit::MeasureUnit(MeasureUnit &&other) noexcept
- : fImpl(other.fImpl),
- fSubTypeId(other.fSubTypeId),
- fTypeId(other.fTypeId) {
- other.fImpl = nullptr;
-}
-
-MeasureUnit::MeasureUnit(MeasureUnitImpl&& impl)
- : fImpl(nullptr), fSubTypeId(-1), fTypeId(-1) {
- if (!findBySubType(impl.identifier.toStringPiece(), this)) {
- fImpl = new MeasureUnitImpl(std::move(impl));
- }
-}
-
+ : fImpl(nullptr) {
+ *this = other;
+}
+
+MeasureUnit::MeasureUnit(MeasureUnit &&other) noexcept
+ : fImpl(other.fImpl),
+ fSubTypeId(other.fSubTypeId),
+ fTypeId(other.fTypeId) {
+ other.fImpl = nullptr;
+}
+
+MeasureUnit::MeasureUnit(MeasureUnitImpl&& impl)
+ : fImpl(nullptr), fSubTypeId(-1), fTypeId(-1) {
+ if (!findBySubType(impl.identifier.toStringPiece(), this)) {
+ fImpl = new MeasureUnitImpl(std::move(impl));
+ }
+}
+
MeasureUnit &MeasureUnit::operator=(const MeasureUnit &other) {
if (this == &other) {
return *this;
}
- delete fImpl;
- if (other.fImpl) {
- ErrorCode localStatus;
- fImpl = new MeasureUnitImpl(other.fImpl->copy(localStatus));
- if (!fImpl || localStatus.isFailure()) {
- // Unrecoverable allocation error; set to the default unit
- *this = MeasureUnit();
- return *this;
- }
- } else {
- fImpl = nullptr;
- }
+ delete fImpl;
+ if (other.fImpl) {
+ ErrorCode localStatus;
+ fImpl = new MeasureUnitImpl(other.fImpl->copy(localStatus));
+ if (!fImpl || localStatus.isFailure()) {
+ // Unrecoverable allocation error; set to the default unit
+ *this = MeasureUnit();
+ return *this;
+ }
+ } else {
+ fImpl = nullptr;
+ }
fTypeId = other.fTypeId;
fSubTypeId = other.fSubTypeId;
return *this;
}
-MeasureUnit &MeasureUnit::operator=(MeasureUnit &&other) noexcept {
- if (this == &other) {
- return *this;
- }
- delete fImpl;
- fImpl = other.fImpl;
- other.fImpl = nullptr;
- fTypeId = other.fTypeId;
- fSubTypeId = other.fSubTypeId;
- return *this;
-}
-
-MeasureUnit *MeasureUnit::clone() const {
+MeasureUnit &MeasureUnit::operator=(MeasureUnit &&other) noexcept {
+ if (this == &other) {
+ return *this;
+ }
+ delete fImpl;
+ fImpl = other.fImpl;
+ other.fImpl = nullptr;
+ fTypeId = other.fTypeId;
+ fSubTypeId = other.fSubTypeId;
+ return *this;
+}
+
+MeasureUnit *MeasureUnit::clone() const {
return new MeasureUnit(*this);
}
MeasureUnit::~MeasureUnit() {
- delete fImpl;
- fImpl = nullptr;
+ delete fImpl;
+ fImpl = nullptr;
}
const char *MeasureUnit::getType() const {
- // We have a type & subtype only if fTypeId is present.
- if (fTypeId == -1) {
- return "";
- }
+ // We have a type & subtype only if fTypeId is present.
+ if (fTypeId == -1) {
+ return "";
+ }
return gTypes[fTypeId];
}
const char *MeasureUnit::getSubtype() const {
- // We have a type & subtype only if fTypeId is present.
- if (fTypeId == -1) {
- return "";
- }
- return getIdentifier();
-}
-
-const char *MeasureUnit::getIdentifier() const {
- return fImpl ? fImpl->identifier.data() : gSubTypes[getOffset()];
+ // We have a type & subtype only if fTypeId is present.
+ if (fTypeId == -1) {
+ return "";
+ }
+ return getIdentifier();
}
+const char *MeasureUnit::getIdentifier() const {
+ return fImpl ? fImpl->identifier.data() : gSubTypes[getOffset()];
+}
+
UBool MeasureUnit::operator==(const UObject& other) const {
if (this == &other) { // Same object, equal
return TRUE;
@@ -2104,7 +2104,7 @@ UBool MeasureUnit::operator==(const UObject& other) const {
return FALSE;
}
const MeasureUnit &rhs = static_cast<const MeasureUnit&>(other);
- return uprv_strcmp(getIdentifier(), rhs.getIdentifier()) == 0;
+ return uprv_strcmp(getIdentifier(), rhs.getIdentifier()) == 0;
}
int32_t MeasureUnit::getIndex() const {
@@ -2189,29 +2189,29 @@ int32_t MeasureUnit::internalGetIndexForTypeAndSubtype(const char *type, const c
return gIndexes[t] + st - gOffsets[t];
}
-bool MeasureUnit::findBySubType(StringPiece subType, MeasureUnit* output) {
- for (int32_t t = 0; t < UPRV_LENGTHOF(gOffsets) - 1; t++) {
- // Skip currency units
- if (gIndexes[t] == gIndexes[t + 1]) {
- continue;
- }
- int32_t st = binarySearch(gSubTypes, gOffsets[t], gOffsets[t + 1], subType);
- if (st >= 0) {
- output->setTo(t, st - gOffsets[t]);
- return true;
- }
- }
- return false;
-}
-
-MeasureUnit MeasureUnit::resolveUnitPerUnit(
- const MeasureUnit &unit, const MeasureUnit &perUnit, bool* isResolved) {
+bool MeasureUnit::findBySubType(StringPiece subType, MeasureUnit* output) {
+ for (int32_t t = 0; t < UPRV_LENGTHOF(gOffsets) - 1; t++) {
+ // Skip currency units
+ if (gIndexes[t] == gIndexes[t + 1]) {
+ continue;
+ }
+ int32_t st = binarySearch(gSubTypes, gOffsets[t], gOffsets[t + 1], subType);
+ if (st >= 0) {
+ output->setTo(t, st - gOffsets[t]);
+ return true;
+ }
+ }
+ return false;
+}
+
+MeasureUnit MeasureUnit::resolveUnitPerUnit(
+ const MeasureUnit &unit, const MeasureUnit &perUnit, bool* isResolved) {
int32_t unitOffset = unit.getOffset();
int32_t perUnitOffset = perUnit.getOffset();
- if (unitOffset == -1 || perUnitOffset == -1) {
- *isResolved = false;
- return MeasureUnit();
- }
+ if (unitOffset == -1 || perUnitOffset == -1) {
+ *isResolved = false;
+ return MeasureUnit();
+ }
// binary search for (unitOffset, perUnitOffset)
int32_t start = 0;
@@ -2230,13 +2230,13 @@ MeasureUnit MeasureUnit::resolveUnitPerUnit(
} else {
// We found a resolution for our unit / per-unit combo
// return it.
- *isResolved = true;
- return MeasureUnit(midRow[2], midRow[3]);
+ *isResolved = true;
+ return MeasureUnit(midRow[2], midRow[3]);
}
}
-
- *isResolved = false;
- return MeasureUnit();
+
+ *isResolved = false;
+ return MeasureUnit();
}
MeasureUnit *MeasureUnit::create(int typeId, int subTypeId, UErrorCode &status) {
@@ -2259,46 +2259,46 @@ void MeasureUnit::initTime(const char *timeId) {
fSubTypeId = result - gOffsets[fTypeId];
}
-void MeasureUnit::initCurrency(StringPiece isoCurrency) {
+void MeasureUnit::initCurrency(StringPiece isoCurrency) {
int32_t result = binarySearch(gTypes, 0, UPRV_LENGTHOF(gTypes), "currency");
U_ASSERT(result != -1);
fTypeId = result;
result = binarySearch(
gSubTypes, gOffsets[fTypeId], gOffsets[fTypeId + 1], isoCurrency);
- if (result == -1) {
- fImpl = new MeasureUnitImpl(MeasureUnitImpl::forCurrencyCode(isoCurrency));
- if (fImpl) {
- fSubTypeId = -1;
- return;
- }
- // malloc error: fall back to the undefined currency
- result = binarySearch(
- gSubTypes, gOffsets[fTypeId], gOffsets[fTypeId + 1], kDefaultCurrency8);
- U_ASSERT(result != -1);
+ if (result == -1) {
+ fImpl = new MeasureUnitImpl(MeasureUnitImpl::forCurrencyCode(isoCurrency));
+ if (fImpl) {
+ fSubTypeId = -1;
+ return;
+ }
+ // malloc error: fall back to the undefined currency
+ result = binarySearch(
+ gSubTypes, gOffsets[fTypeId], gOffsets[fTypeId + 1], kDefaultCurrency8);
+ U_ASSERT(result != -1);
}
- fSubTypeId = result - gOffsets[fTypeId];
-}
-
-void MeasureUnit::initNoUnit(const char *subtype) {
- int32_t result = binarySearch(gTypes, 0, UPRV_LENGTHOF(gTypes), "none");
- U_ASSERT(result != -1);
- fTypeId = result;
- result = binarySearch(gSubTypes, gOffsets[fTypeId], gOffsets[fTypeId + 1], subtype);
- U_ASSERT(result != -1);
- fSubTypeId = result - gOffsets[fTypeId];
+ fSubTypeId = result - gOffsets[fTypeId];
}
+void MeasureUnit::initNoUnit(const char *subtype) {
+ int32_t result = binarySearch(gTypes, 0, UPRV_LENGTHOF(gTypes), "none");
+ U_ASSERT(result != -1);
+ fTypeId = result;
+ result = binarySearch(gSubTypes, gOffsets[fTypeId], gOffsets[fTypeId + 1], subtype);
+ U_ASSERT(result != -1);
+ fSubTypeId = result - gOffsets[fTypeId];
+}
+
void MeasureUnit::setTo(int32_t typeId, int32_t subTypeId) {
fTypeId = typeId;
fSubTypeId = subTypeId;
- delete fImpl;
- fImpl = nullptr;
+ delete fImpl;
+ fImpl = nullptr;
}
int32_t MeasureUnit::getOffset() const {
- if (fTypeId < 0 || fSubTypeId < 0) {
- return -1;
- }
+ if (fTypeId < 0 || fSubTypeId < 0) {
+ return -1;
+ }
return gOffsets[fTypeId] + fSubTypeId;
}
diff --git a/contrib/libs/icu/i18n/measunit_extra.cpp b/contrib/libs/icu/i18n/measunit_extra.cpp
index aeb60017a1..ab2b40d9b7 100644
--- a/contrib/libs/icu/i18n/measunit_extra.cpp
+++ b/contrib/libs/icu/i18n/measunit_extra.cpp
@@ -1,893 +1,893 @@
-// © 2020 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html
-
-// Extra functions for MeasureUnit not needed for all clients.
-// Separate .o file so that it can be removed for modularity.
-
-#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 <cstdlib>
-#include "cstring.h"
-#include "measunit_impl.h"
-#include "uarrsort.h"
-#include "uassert.h"
-#include "ucln_in.h"
-#include "umutex.h"
-#include "unicode/errorcode.h"
-#include "unicode/localpointer.h"
-#include "unicode/measunit.h"
-#include "unicode/ucharstrie.h"
-#include "unicode/ucharstriebuilder.h"
-
-#include "cstr.h"
-
-U_NAMESPACE_BEGIN
-
-
-namespace {
-
-// TODO: Propose a new error code for this?
-constexpr UErrorCode kUnitIdentifierSyntaxError = U_ILLEGAL_ARGUMENT_ERROR;
-
-// Trie value offset for SI Prefixes. This is big enough to ensure we only
-// insert positive integers into the trie.
-constexpr int32_t kSIPrefixOffset = 64;
-
-// Trie value offset for compound parts, e.g. "-per-", "-", "-and-".
-constexpr int32_t kCompoundPartOffset = 128;
-
-enum CompoundPart {
- // Represents "-per-"
- COMPOUND_PART_PER = kCompoundPartOffset,
- // Represents "-"
- COMPOUND_PART_TIMES,
- // Represents "-and-"
- COMPOUND_PART_AND,
-};
-
-// Trie value offset for "per-".
-constexpr int32_t kInitialCompoundPartOffset = 192;
-
-enum InitialCompoundPart {
- // Represents "per-", the only compound part that can appear at the start of
- // an identifier.
- INITIAL_COMPOUND_PART_PER = kInitialCompoundPartOffset,
-};
-
-// Trie value offset for powers like "square-", "cubic-", "p2-" etc.
-constexpr int32_t kPowerPartOffset = 256;
-
-enum PowerPart {
- POWER_PART_P2 = kPowerPartOffset + 2,
- POWER_PART_P3,
- POWER_PART_P4,
- POWER_PART_P5,
- POWER_PART_P6,
- POWER_PART_P7,
- POWER_PART_P8,
- POWER_PART_P9,
- POWER_PART_P10,
- POWER_PART_P11,
- POWER_PART_P12,
- POWER_PART_P13,
- POWER_PART_P14,
- POWER_PART_P15,
-};
-
-// Trie value offset for simple units, e.g. "gram", "nautical-mile",
-// "fluid-ounce-imperial".
-constexpr int32_t kSimpleUnitOffset = 512;
-
-const struct SIPrefixStrings {
- const char* const string;
- UMeasureSIPrefix value;
-} gSIPrefixStrings[] = {
- { "yotta", UMEASURE_SI_PREFIX_YOTTA },
- { "zetta", UMEASURE_SI_PREFIX_ZETTA },
- { "exa", UMEASURE_SI_PREFIX_EXA },
- { "peta", UMEASURE_SI_PREFIX_PETA },
- { "tera", UMEASURE_SI_PREFIX_TERA },
- { "giga", UMEASURE_SI_PREFIX_GIGA },
- { "mega", UMEASURE_SI_PREFIX_MEGA },
- { "kilo", UMEASURE_SI_PREFIX_KILO },
- { "hecto", UMEASURE_SI_PREFIX_HECTO },
- { "deka", UMEASURE_SI_PREFIX_DEKA },
- { "deci", UMEASURE_SI_PREFIX_DECI },
- { "centi", UMEASURE_SI_PREFIX_CENTI },
- { "milli", UMEASURE_SI_PREFIX_MILLI },
- { "micro", UMEASURE_SI_PREFIX_MICRO },
- { "nano", UMEASURE_SI_PREFIX_NANO },
- { "pico", UMEASURE_SI_PREFIX_PICO },
- { "femto", UMEASURE_SI_PREFIX_FEMTO },
- { "atto", UMEASURE_SI_PREFIX_ATTO },
- { "zepto", UMEASURE_SI_PREFIX_ZEPTO },
- { "yocto", UMEASURE_SI_PREFIX_YOCTO },
-};
-
-// TODO(ICU-21059): Get this list from data
-const char16_t* const gSimpleUnits[] = {
- u"candela",
- u"carat",
- u"gram",
- u"ounce",
- u"ounce-troy",
- u"pound",
- u"kilogram",
- u"stone",
- u"ton",
- u"metric-ton",
- u"earth-mass",
- u"solar-mass",
- u"point",
- u"inch",
- u"foot",
- u"yard",
- u"meter",
- u"fathom",
- u"furlong",
- u"mile",
- u"nautical-mile",
- u"mile-scandinavian",
- u"100-kilometer",
- u"earth-radius",
- u"solar-radius",
- u"astronomical-unit",
- u"light-year",
- u"parsec",
- u"second",
- u"minute",
- u"hour",
- u"day",
- u"day-person",
- u"week",
- u"week-person",
- u"month",
- u"month-person",
- u"year",
- u"year-person",
- u"decade",
- u"century",
- u"ampere",
- u"fahrenheit",
- u"kelvin",
- u"celsius",
- u"arc-second",
- u"arc-minute",
- u"degree",
- u"radian",
- u"revolution",
- u"item",
- u"mole",
- u"permillion",
- u"permyriad",
- u"permille",
- u"percent",
- u"karat",
- u"portion",
- u"bit",
- u"byte",
- u"dot",
- u"pixel",
- u"em",
- u"hertz",
- u"newton",
- u"pound-force",
- u"pascal",
- u"bar",
- u"atmosphere",
- u"ofhg",
- u"electronvolt",
- u"dalton",
- u"joule",
- u"calorie",
- u"british-thermal-unit",
- u"foodcalorie",
- u"therm-us",
- u"watt",
- u"horsepower",
- u"solar-luminosity",
- u"volt",
- u"ohm",
- u"dunam",
- u"acre",
- u"hectare",
- u"teaspoon",
- u"tablespoon",
- u"fluid-ounce-imperial",
- u"fluid-ounce",
- u"cup",
- u"cup-metric",
- u"pint",
- u"pint-metric",
- u"quart",
- u"liter",
- u"gallon",
- u"gallon-imperial",
- u"bushel",
- u"barrel",
- u"knot",
- u"g-force",
- u"lux",
-};
-
-icu::UInitOnce gUnitExtrasInitOnce = U_INITONCE_INITIALIZER;
-
-char16_t* kSerializedUnitExtrasStemTrie = nullptr;
-
-UBool U_CALLCONV cleanupUnitExtras() {
- uprv_free(kSerializedUnitExtrasStemTrie);
- kSerializedUnitExtrasStemTrie = nullptr;
- gUnitExtrasInitOnce.reset();
- return TRUE;
-}
-
-void U_CALLCONV initUnitExtras(UErrorCode& status) {
- ucln_i18n_registerCleanup(UCLN_I18N_UNIT_EXTRAS, cleanupUnitExtras);
-
- UCharsTrieBuilder b(status);
- if (U_FAILURE(status)) { return; }
-
- // Add SI prefixes
- for (const auto& siPrefixInfo : gSIPrefixStrings) {
- UnicodeString uSIPrefix(siPrefixInfo.string, -1, US_INV);
- b.add(uSIPrefix, siPrefixInfo.value + kSIPrefixOffset, status);
- }
- if (U_FAILURE(status)) { return; }
-
- // Add syntax parts (compound, power prefixes)
- b.add(u"-per-", COMPOUND_PART_PER, status);
- b.add(u"-", COMPOUND_PART_TIMES, status);
- b.add(u"-and-", COMPOUND_PART_AND, status);
- b.add(u"per-", INITIAL_COMPOUND_PART_PER, status);
- b.add(u"square-", POWER_PART_P2, status);
- b.add(u"cubic-", POWER_PART_P3, status);
- b.add(u"p2-", POWER_PART_P2, status);
- b.add(u"p3-", POWER_PART_P3, status);
- b.add(u"p4-", POWER_PART_P4, status);
- b.add(u"p5-", POWER_PART_P5, status);
- b.add(u"p6-", POWER_PART_P6, status);
- b.add(u"p7-", POWER_PART_P7, status);
- b.add(u"p8-", POWER_PART_P8, status);
- b.add(u"p9-", POWER_PART_P9, status);
- b.add(u"p10-", POWER_PART_P10, status);
- b.add(u"p11-", POWER_PART_P11, status);
- b.add(u"p12-", POWER_PART_P12, status);
- b.add(u"p13-", POWER_PART_P13, status);
- b.add(u"p14-", POWER_PART_P14, status);
- b.add(u"p15-", POWER_PART_P15, status);
- if (U_FAILURE(status)) { return; }
-
- // Add sanctioned simple units by offset
- int32_t simpleUnitOffset = kSimpleUnitOffset;
- for (auto simpleUnit : gSimpleUnits) {
- b.add(simpleUnit, simpleUnitOffset++, status);
- }
-
- // 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);
- kSerializedUnitExtrasStemTrie = static_cast<char16_t*>(uprv_malloc(numBytes));
- uprv_memcpy(kSerializedUnitExtrasStemTrie, result.getBuffer(), numBytes);
-}
-
-class Token {
-public:
- Token(int32_t match) : fMatch(match) {}
-
- enum Type {
- TYPE_UNDEFINED,
- TYPE_SI_PREFIX,
- // Token type for "-per-", "-", and "-and-".
- TYPE_COMPOUND_PART,
- // Token type for "per-".
- TYPE_INITIAL_COMPOUND_PART,
- TYPE_POWER_PART,
- TYPE_SIMPLE_UNIT,
- };
-
- // Calling getType() is invalid, resulting in an assertion failure, if Token
- // value isn't positive.
- Type getType() const {
- U_ASSERT(fMatch > 0);
- if (fMatch < kCompoundPartOffset) {
- return TYPE_SI_PREFIX;
- }
- if (fMatch < kInitialCompoundPartOffset) {
- return TYPE_COMPOUND_PART;
- }
- if (fMatch < kPowerPartOffset) {
- return TYPE_INITIAL_COMPOUND_PART;
- }
- if (fMatch < kSimpleUnitOffset) {
- return TYPE_POWER_PART;
- }
- return TYPE_SIMPLE_UNIT;
- }
-
- UMeasureSIPrefix getSIPrefix() const {
- U_ASSERT(getType() == TYPE_SI_PREFIX);
- return static_cast<UMeasureSIPrefix>(fMatch - kSIPrefixOffset);
- }
-
- // Valid only for tokens with type TYPE_COMPOUND_PART.
- int32_t getMatch() const {
- U_ASSERT(getType() == TYPE_COMPOUND_PART);
- return fMatch;
- }
-
- int32_t getInitialCompoundPart() const {
- // Even if there is only one InitialCompoundPart value, we have this
- // function for the simplicity of code consistency.
- U_ASSERT(getType() == TYPE_INITIAL_COMPOUND_PART);
- // Defensive: if this assert fails, code using this function also needs
- // to change.
- U_ASSERT(fMatch == INITIAL_COMPOUND_PART_PER);
- return fMatch;
- }
-
- int8_t getPower() const {
- U_ASSERT(getType() == TYPE_POWER_PART);
- return static_cast<int8_t>(fMatch - kPowerPartOffset);
- }
-
- int32_t getSimpleUnitIndex() const {
- U_ASSERT(getType() == TYPE_SIMPLE_UNIT);
- return fMatch - kSimpleUnitOffset;
- }
-
-private:
- int32_t fMatch;
-};
-
-class Parser {
-public:
- /**
- * Factory function for parsing the given identifier.
- *
- * @param source The identifier to parse. This function does not make a copy
- * of source: the underlying string that source points at, must outlive the
- * parser.
- * @param status ICU error code.
- */
- static Parser from(StringPiece source, UErrorCode& status) {
- if (U_FAILURE(status)) {
- return Parser();
- }
- umtx_initOnce(gUnitExtrasInitOnce, &initUnitExtras, status);
- if (U_FAILURE(status)) {
- return Parser();
- }
- return Parser(source);
- }
-
- MeasureUnitImpl parse(UErrorCode& status) {
- MeasureUnitImpl result;
- parseImpl(result, status);
- return result;
- }
-
-private:
- // Tracks parser progress: the offset into fSource.
- int32_t fIndex = 0;
-
- // Since we're not owning this memory, whatever is passed to the constructor
- // should live longer than this Parser - and the parser shouldn't return any
- // references to that string.
- StringPiece fSource;
- UCharsTrie fTrie;
-
- // Set to true when we've seen a "-per-" or a "per-", after which all units
- // are in the denominator. Until we find an "-and-", at which point the
- // identifier is invalid pending TODO(CLDR-13700).
- bool fAfterPer = false;
-
- Parser() : fSource(""), fTrie(u"") {}
-
- Parser(StringPiece source)
- : fSource(source), fTrie(kSerializedUnitExtrasStemTrie) {}
-
- inline bool hasNext() const {
- return fIndex < fSource.length();
- }
-
- // Returns the next Token parsed from fSource, advancing fIndex to the end
- // of that token in fSource. In case of U_FAILURE(status), the token
- // returned will cause an abort if getType() is called on it.
- Token nextToken(UErrorCode& status) {
- fTrie.reset();
- int32_t match = -1;
- // Saves the position in the fSource string for the end of the most
- // recent matching token.
- int32_t previ = -1;
- // Find the longest token that matches a value in the trie:
- while (fIndex < fSource.length()) {
- auto result = fTrie.next(fSource.data()[fIndex++]);
- if (result == USTRINGTRIE_NO_MATCH) {
- break;
- } else if (result == USTRINGTRIE_NO_VALUE) {
- continue;
- }
- U_ASSERT(USTRINGTRIE_HAS_VALUE(result));
- match = fTrie.getValue();
- previ = fIndex;
- if (result == USTRINGTRIE_FINAL_VALUE) {
- break;
- }
- U_ASSERT(result == USTRINGTRIE_INTERMEDIATE_VALUE);
- // continue;
- }
-
- if (match < 0) {
- status = kUnitIdentifierSyntaxError;
- } else {
- fIndex = previ;
- }
- return Token(match);
- }
-
- /**
- * Returns the next "single unit" via result.
- *
- * If a "-per-" was parsed, the result will have appropriate negative
- * dimensionality.
- *
- * Returns an error if we parse both compound units and "-and-", since mixed
- * compound units are not yet supported - TODO(CLDR-13700).
- *
- * @param result Will be overwritten by the result, if status shows success.
- * @param sawAnd If an "-and-" was parsed prior to finding the "single
- * unit", sawAnd is set to true. If not, it is left as is.
- * @param status ICU error code.
- */
- void nextSingleUnit(SingleUnitImpl& result, bool& sawAnd, UErrorCode& status) {
- if (U_FAILURE(status)) {
- return;
- }
-
- // state:
- // 0 = no tokens seen yet (will accept power, SI prefix, or simple unit)
- // 1 = power token seen (will not accept another power token)
- // 2 = SI prefix token seen (will not accept a power or SI prefix token)
- int32_t state = 0;
-
- bool atStart = fIndex == 0;
- Token token = nextToken(status);
- if (U_FAILURE(status)) { return; }
-
- if (atStart) {
- // Identifiers optionally start with "per-".
- if (token.getType() == Token::TYPE_INITIAL_COMPOUND_PART) {
- U_ASSERT(token.getInitialCompoundPart() == INITIAL_COMPOUND_PART_PER);
- fAfterPer = true;
- result.dimensionality = -1;
-
- token = nextToken(status);
- if (U_FAILURE(status)) { return; }
- }
- } else {
- // All other SingleUnit's are separated from previous SingleUnit's
- // via a compound part:
- if (token.getType() != Token::TYPE_COMPOUND_PART) {
- status = kUnitIdentifierSyntaxError;
- return;
- }
-
- switch (token.getMatch()) {
- case COMPOUND_PART_PER:
- if (sawAnd) {
- // Mixed compound units not yet supported,
- // TODO(CLDR-13700).
- status = kUnitIdentifierSyntaxError;
- return;
- }
- fAfterPer = true;
- result.dimensionality = -1;
- break;
-
- case COMPOUND_PART_TIMES:
- if (fAfterPer) {
- result.dimensionality = -1;
- }
- break;
-
- case COMPOUND_PART_AND:
- if (fAfterPer) {
- // Can't start with "-and-", and mixed compound units
- // not yet supported, TODO(CLDR-13700).
- status = kUnitIdentifierSyntaxError;
- return;
- }
- sawAnd = true;
- break;
- }
-
- token = nextToken(status);
- if (U_FAILURE(status)) { return; }
- }
-
- // Read tokens until we have a complete SingleUnit or we reach the end.
- while (true) {
- switch (token.getType()) {
- case Token::TYPE_POWER_PART:
- if (state > 0) {
- status = kUnitIdentifierSyntaxError;
- return;
- }
- result.dimensionality *= token.getPower();
- state = 1;
- break;
-
- case Token::TYPE_SI_PREFIX:
- if (state > 1) {
- status = kUnitIdentifierSyntaxError;
- return;
- }
- result.siPrefix = token.getSIPrefix();
- state = 2;
- break;
-
- case Token::TYPE_SIMPLE_UNIT:
- result.index = token.getSimpleUnitIndex();
- return;
-
- default:
- status = kUnitIdentifierSyntaxError;
- return;
- }
-
- if (!hasNext()) {
- // We ran out of tokens before finding a complete single unit.
- status = kUnitIdentifierSyntaxError;
- return;
- }
- token = nextToken(status);
- if (U_FAILURE(status)) {
- return;
- }
- }
- }
-
- /// @param result is modified, not overridden. Caller must pass in a
- /// default-constructed (empty) MeasureUnitImpl instance.
- void parseImpl(MeasureUnitImpl& result, UErrorCode& status) {
- if (U_FAILURE(status)) {
- return;
- }
- if (fSource.empty()) {
- // The dimenionless unit: nothing to parse. leave result as is.
- return;
- }
- int32_t unitNum = 0;
- while (hasNext()) {
- bool sawAnd = false;
- SingleUnitImpl singleUnit;
- nextSingleUnit(singleUnit, sawAnd, status);
- if (U_FAILURE(status)) {
- return;
- }
- U_ASSERT(!singleUnit.isDimensionless());
- bool added = result.append(singleUnit, status);
- if (sawAnd && !added) {
- // Two similar units are not allowed in a mixed unit
- status = kUnitIdentifierSyntaxError;
- return;
- }
- if ((++unitNum) >= 2) {
- // nextSingleUnit fails appropriately for "per" and "and" in the
- // same identifier. It doesn't fail for other compound units
- // (COMPOUND_PART_TIMES). Consequently we take care of that
- // here.
- UMeasureUnitComplexity complexity =
- sawAnd ? UMEASURE_UNIT_MIXED : UMEASURE_UNIT_COMPOUND;
- if (unitNum == 2) {
- U_ASSERT(result.complexity == UMEASURE_UNIT_SINGLE);
- result.complexity = complexity;
- } else if (result.complexity != complexity) {
- // Can't have mixed compound units
- status = kUnitIdentifierSyntaxError;
- return;
- }
- }
- }
- }
-};
-
-int32_t U_CALLCONV
-compareSingleUnits(const void* /*context*/, const void* left, const void* right) {
- auto realLeft = static_cast<const SingleUnitImpl* const*>(left);
- auto realRight = static_cast<const SingleUnitImpl* const*>(right);
- return (*realLeft)->compareTo(**realRight);
-}
-
-/**
- * Generate the identifier string for a single unit in place.
- *
- * Does not support the dimensionless SingleUnitImpl: calling serializeSingle
- * with the dimensionless unit results in an U_INTERNAL_PROGRAM_ERROR.
- *
- * @param first If singleUnit is part of a compound unit, and not its first
- * single unit, set this to false. Otherwise: set to true.
- */
-void serializeSingle(const SingleUnitImpl& singleUnit, bool first, CharString& output, UErrorCode& status) {
- if (first && singleUnit.dimensionality < 0) {
- // Essentially the "unary per". For compound units with a numerator, the
- // caller takes care of the "binary per".
- output.append("per-", status);
- }
-
- if (singleUnit.isDimensionless()) {
- status = U_INTERNAL_PROGRAM_ERROR;
- return;
- }
- int8_t posPower = std::abs(singleUnit.dimensionality);
- if (posPower == 0) {
- status = U_INTERNAL_PROGRAM_ERROR;
- } else if (posPower == 1) {
- // no-op
- } else if (posPower == 2) {
- output.append("square-", status);
- } else if (posPower == 3) {
- output.append("cubic-", status);
- } else if (posPower < 10) {
- output.append('p', status);
- output.append(posPower + '0', status);
- output.append('-', status);
- } else if (posPower <= 15) {
- output.append("p1", status);
- output.append('0' + (posPower % 10), status);
- output.append('-', status);
- } else {
- status = kUnitIdentifierSyntaxError;
- }
- if (U_FAILURE(status)) {
- return;
- }
-
- if (singleUnit.siPrefix != UMEASURE_SI_PREFIX_ONE) {
- for (const auto& siPrefixInfo : gSIPrefixStrings) {
- if (siPrefixInfo.value == singleUnit.siPrefix) {
- output.append(siPrefixInfo.string, status);
- break;
- }
- }
- }
- if (U_FAILURE(status)) {
- return;
- }
-
- output.appendInvariantChars(gSimpleUnits[singleUnit.index], status);
-}
-
-/**
- * Normalize a MeasureUnitImpl and generate the identifier string in place.
- */
-void serialize(MeasureUnitImpl& impl, UErrorCode& status) {
- if (U_FAILURE(status)) {
- return;
- }
- U_ASSERT(impl.identifier.isEmpty());
- if (impl.units.length() == 0) {
- // Dimensionless, constructed by the default constructor: no appending
- // to impl.identifier, we wish it to contain the zero-length string.
- return;
- }
- if (impl.complexity == UMEASURE_UNIT_COMPOUND) {
- // Note: don't sort a MIXED unit
- uprv_sortArray(
- impl.units.getAlias(),
- impl.units.length(),
- sizeof(impl.units[0]),
- compareSingleUnits,
- nullptr,
- false,
- &status);
- if (U_FAILURE(status)) {
- return;
- }
- }
- serializeSingle(*impl.units[0], true, impl.identifier, status);
- if (impl.units.length() == 1) {
- return;
- }
- for (int32_t i = 1; i < impl.units.length(); i++) {
- const SingleUnitImpl& prev = *impl.units[i-1];
- const SingleUnitImpl& curr = *impl.units[i];
- if (impl.complexity == UMEASURE_UNIT_MIXED) {
- impl.identifier.append("-and-", status);
- serializeSingle(curr, true, impl.identifier, status);
- } else {
- if (prev.dimensionality > 0 && curr.dimensionality < 0) {
- impl.identifier.append("-per-", status);
- } else {
- impl.identifier.append('-', status);
- }
- serializeSingle(curr, false, impl.identifier, status);
- }
- }
-
-}
-
-/**
- * Appends a SingleUnitImpl to a MeasureUnitImpl.
- *
- * @return true if a new item was added. If unit is the dimensionless unit, it
- * is never added: the return value will always be false.
- */
-bool appendImpl(MeasureUnitImpl& impl, const SingleUnitImpl& unit, UErrorCode& status) {
- if (unit.isDimensionless()) {
- // We don't append dimensionless units.
- return false;
- }
- // Find a similar unit that already exists, to attempt to coalesce
- SingleUnitImpl* oldUnit = nullptr;
- for (int32_t i = 0; i < impl.units.length(); i++) {
- auto* candidate = impl.units[i];
- if (candidate->isCompatibleWith(unit)) {
- oldUnit = candidate;
- }
- }
- if (oldUnit) {
- // Both dimensionalities will be positive, or both will be negative, by
- // virtue of isCompatibleWith().
- oldUnit->dimensionality += unit.dimensionality;
- } else {
- SingleUnitImpl* destination = impl.units.emplaceBack();
- if (!destination) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return false;
- }
- *destination = unit;
- }
- return (oldUnit == nullptr);
-}
-
-} // namespace
-
-
-SingleUnitImpl SingleUnitImpl::forMeasureUnit(const MeasureUnit& measureUnit, UErrorCode& status) {
- MeasureUnitImpl temp;
- const MeasureUnitImpl& impl = MeasureUnitImpl::forMeasureUnit(measureUnit, temp, status);
- if (U_FAILURE(status)) {
- return {};
- }
- if (impl.units.length() == 0) {
- return {};
- }
- if (impl.units.length() == 1) {
- return *impl.units[0];
- }
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return {};
-}
-
-MeasureUnit SingleUnitImpl::build(UErrorCode& status) const {
- MeasureUnitImpl temp;
- temp.append(*this, status);
- return std::move(temp).build(status);
-}
-
-
-MeasureUnitImpl MeasureUnitImpl::forIdentifier(StringPiece identifier, UErrorCode& status) {
- return Parser::from(identifier, status).parse(status);
-}
-
-const MeasureUnitImpl& MeasureUnitImpl::forMeasureUnit(
- const MeasureUnit& measureUnit, MeasureUnitImpl& memory, UErrorCode& status) {
- if (measureUnit.fImpl) {
- return *measureUnit.fImpl;
- } else {
- memory = Parser::from(measureUnit.getIdentifier(), status).parse(status);
- return memory;
- }
-}
-
-MeasureUnitImpl MeasureUnitImpl::forMeasureUnitMaybeCopy(
- const MeasureUnit& measureUnit, UErrorCode& status) {
- if (measureUnit.fImpl) {
- return measureUnit.fImpl->copy(status);
- } else {
- return Parser::from(measureUnit.getIdentifier(), status).parse(status);
- }
-}
-
-void MeasureUnitImpl::takeReciprocal(UErrorCode& /*status*/) {
- identifier.clear();
- for (int32_t i = 0; i < units.length(); i++) {
- units[i]->dimensionality *= -1;
- }
-}
-
-bool MeasureUnitImpl::append(const SingleUnitImpl& singleUnit, UErrorCode& status) {
- identifier.clear();
- return appendImpl(*this, singleUnit, status);
-}
-
-MeasureUnit MeasureUnitImpl::build(UErrorCode& status) && {
- serialize(*this, status);
- return MeasureUnit(std::move(*this));
-}
-
-
-MeasureUnit MeasureUnit::forIdentifier(StringPiece identifier, UErrorCode& status) {
- return Parser::from(identifier, status).parse(status).build(status);
-}
-
-UMeasureUnitComplexity MeasureUnit::getComplexity(UErrorCode& status) const {
- MeasureUnitImpl temp;
- return MeasureUnitImpl::forMeasureUnit(*this, temp, status).complexity;
-}
-
-UMeasureSIPrefix MeasureUnit::getSIPrefix(UErrorCode& status) const {
- return SingleUnitImpl::forMeasureUnit(*this, status).siPrefix;
-}
-
-MeasureUnit MeasureUnit::withSIPrefix(UMeasureSIPrefix prefix, UErrorCode& status) const {
- SingleUnitImpl singleUnit = SingleUnitImpl::forMeasureUnit(*this, status);
- singleUnit.siPrefix = prefix;
- return singleUnit.build(status);
-}
-
-int32_t MeasureUnit::getDimensionality(UErrorCode& status) const {
- SingleUnitImpl singleUnit = SingleUnitImpl::forMeasureUnit(*this, status);
- if (U_FAILURE(status)) { return 0; }
- if (singleUnit.isDimensionless()) {
- return 0;
- }
- return singleUnit.dimensionality;
-}
-
-MeasureUnit MeasureUnit::withDimensionality(int32_t dimensionality, UErrorCode& status) const {
- SingleUnitImpl singleUnit = SingleUnitImpl::forMeasureUnit(*this, status);
- singleUnit.dimensionality = dimensionality;
- return singleUnit.build(status);
-}
-
-MeasureUnit MeasureUnit::reciprocal(UErrorCode& status) const {
- MeasureUnitImpl impl = MeasureUnitImpl::forMeasureUnitMaybeCopy(*this, status);
- impl.takeReciprocal(status);
- return std::move(impl).build(status);
-}
-
-MeasureUnit MeasureUnit::product(const MeasureUnit& other, UErrorCode& status) const {
- MeasureUnitImpl impl = MeasureUnitImpl::forMeasureUnitMaybeCopy(*this, status);
- MeasureUnitImpl temp;
- const MeasureUnitImpl& otherImpl = MeasureUnitImpl::forMeasureUnit(other, temp, status);
- if (impl.complexity == UMEASURE_UNIT_MIXED || otherImpl.complexity == UMEASURE_UNIT_MIXED) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return {};
- }
- for (int32_t i = 0; i < otherImpl.units.length(); i++) {
- impl.append(*otherImpl.units[i], status);
- }
- if (impl.units.length() > 1) {
- impl.complexity = UMEASURE_UNIT_COMPOUND;
- }
- return std::move(impl).build(status);
-}
-
-LocalArray<MeasureUnit> MeasureUnit::splitToSingleUnits(int32_t& outCount, UErrorCode& status) const {
- MeasureUnitImpl temp;
- const MeasureUnitImpl& impl = MeasureUnitImpl::forMeasureUnit(*this, temp, status);
- outCount = impl.units.length();
- MeasureUnit* arr = new MeasureUnit[outCount];
- for (int32_t i = 0; i < outCount; i++) {
- arr[i] = impl.units[i]->build(status);
- }
- return LocalArray<MeasureUnit>(arr, status);
-}
-
-
-U_NAMESPACE_END
-
-#endif /* !UNCONFIG_NO_FORMATTING */
+// © 2020 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+// Extra functions for MeasureUnit not needed for all clients.
+// Separate .o file so that it can be removed for modularity.
+
+#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 <cstdlib>
+#include "cstring.h"
+#include "measunit_impl.h"
+#include "uarrsort.h"
+#include "uassert.h"
+#include "ucln_in.h"
+#include "umutex.h"
+#include "unicode/errorcode.h"
+#include "unicode/localpointer.h"
+#include "unicode/measunit.h"
+#include "unicode/ucharstrie.h"
+#include "unicode/ucharstriebuilder.h"
+
+#include "cstr.h"
+
+U_NAMESPACE_BEGIN
+
+
+namespace {
+
+// TODO: Propose a new error code for this?
+constexpr UErrorCode kUnitIdentifierSyntaxError = U_ILLEGAL_ARGUMENT_ERROR;
+
+// Trie value offset for SI Prefixes. This is big enough to ensure we only
+// insert positive integers into the trie.
+constexpr int32_t kSIPrefixOffset = 64;
+
+// Trie value offset for compound parts, e.g. "-per-", "-", "-and-".
+constexpr int32_t kCompoundPartOffset = 128;
+
+enum CompoundPart {
+ // Represents "-per-"
+ COMPOUND_PART_PER = kCompoundPartOffset,
+ // Represents "-"
+ COMPOUND_PART_TIMES,
+ // Represents "-and-"
+ COMPOUND_PART_AND,
+};
+
+// Trie value offset for "per-".
+constexpr int32_t kInitialCompoundPartOffset = 192;
+
+enum InitialCompoundPart {
+ // Represents "per-", the only compound part that can appear at the start of
+ // an identifier.
+ INITIAL_COMPOUND_PART_PER = kInitialCompoundPartOffset,
+};
+
+// Trie value offset for powers like "square-", "cubic-", "p2-" etc.
+constexpr int32_t kPowerPartOffset = 256;
+
+enum PowerPart {
+ POWER_PART_P2 = kPowerPartOffset + 2,
+ POWER_PART_P3,
+ POWER_PART_P4,
+ POWER_PART_P5,
+ POWER_PART_P6,
+ POWER_PART_P7,
+ POWER_PART_P8,
+ POWER_PART_P9,
+ POWER_PART_P10,
+ POWER_PART_P11,
+ POWER_PART_P12,
+ POWER_PART_P13,
+ POWER_PART_P14,
+ POWER_PART_P15,
+};
+
+// Trie value offset for simple units, e.g. "gram", "nautical-mile",
+// "fluid-ounce-imperial".
+constexpr int32_t kSimpleUnitOffset = 512;
+
+const struct SIPrefixStrings {
+ const char* const string;
+ UMeasureSIPrefix value;
+} gSIPrefixStrings[] = {
+ { "yotta", UMEASURE_SI_PREFIX_YOTTA },
+ { "zetta", UMEASURE_SI_PREFIX_ZETTA },
+ { "exa", UMEASURE_SI_PREFIX_EXA },
+ { "peta", UMEASURE_SI_PREFIX_PETA },
+ { "tera", UMEASURE_SI_PREFIX_TERA },
+ { "giga", UMEASURE_SI_PREFIX_GIGA },
+ { "mega", UMEASURE_SI_PREFIX_MEGA },
+ { "kilo", UMEASURE_SI_PREFIX_KILO },
+ { "hecto", UMEASURE_SI_PREFIX_HECTO },
+ { "deka", UMEASURE_SI_PREFIX_DEKA },
+ { "deci", UMEASURE_SI_PREFIX_DECI },
+ { "centi", UMEASURE_SI_PREFIX_CENTI },
+ { "milli", UMEASURE_SI_PREFIX_MILLI },
+ { "micro", UMEASURE_SI_PREFIX_MICRO },
+ { "nano", UMEASURE_SI_PREFIX_NANO },
+ { "pico", UMEASURE_SI_PREFIX_PICO },
+ { "femto", UMEASURE_SI_PREFIX_FEMTO },
+ { "atto", UMEASURE_SI_PREFIX_ATTO },
+ { "zepto", UMEASURE_SI_PREFIX_ZEPTO },
+ { "yocto", UMEASURE_SI_PREFIX_YOCTO },
+};
+
+// TODO(ICU-21059): Get this list from data
+const char16_t* const gSimpleUnits[] = {
+ u"candela",
+ u"carat",
+ u"gram",
+ u"ounce",
+ u"ounce-troy",
+ u"pound",
+ u"kilogram",
+ u"stone",
+ u"ton",
+ u"metric-ton",
+ u"earth-mass",
+ u"solar-mass",
+ u"point",
+ u"inch",
+ u"foot",
+ u"yard",
+ u"meter",
+ u"fathom",
+ u"furlong",
+ u"mile",
+ u"nautical-mile",
+ u"mile-scandinavian",
+ u"100-kilometer",
+ u"earth-radius",
+ u"solar-radius",
+ u"astronomical-unit",
+ u"light-year",
+ u"parsec",
+ u"second",
+ u"minute",
+ u"hour",
+ u"day",
+ u"day-person",
+ u"week",
+ u"week-person",
+ u"month",
+ u"month-person",
+ u"year",
+ u"year-person",
+ u"decade",
+ u"century",
+ u"ampere",
+ u"fahrenheit",
+ u"kelvin",
+ u"celsius",
+ u"arc-second",
+ u"arc-minute",
+ u"degree",
+ u"radian",
+ u"revolution",
+ u"item",
+ u"mole",
+ u"permillion",
+ u"permyriad",
+ u"permille",
+ u"percent",
+ u"karat",
+ u"portion",
+ u"bit",
+ u"byte",
+ u"dot",
+ u"pixel",
+ u"em",
+ u"hertz",
+ u"newton",
+ u"pound-force",
+ u"pascal",
+ u"bar",
+ u"atmosphere",
+ u"ofhg",
+ u"electronvolt",
+ u"dalton",
+ u"joule",
+ u"calorie",
+ u"british-thermal-unit",
+ u"foodcalorie",
+ u"therm-us",
+ u"watt",
+ u"horsepower",
+ u"solar-luminosity",
+ u"volt",
+ u"ohm",
+ u"dunam",
+ u"acre",
+ u"hectare",
+ u"teaspoon",
+ u"tablespoon",
+ u"fluid-ounce-imperial",
+ u"fluid-ounce",
+ u"cup",
+ u"cup-metric",
+ u"pint",
+ u"pint-metric",
+ u"quart",
+ u"liter",
+ u"gallon",
+ u"gallon-imperial",
+ u"bushel",
+ u"barrel",
+ u"knot",
+ u"g-force",
+ u"lux",
+};
+
+icu::UInitOnce gUnitExtrasInitOnce = U_INITONCE_INITIALIZER;
+
+char16_t* kSerializedUnitExtrasStemTrie = nullptr;
+
+UBool U_CALLCONV cleanupUnitExtras() {
+ uprv_free(kSerializedUnitExtrasStemTrie);
+ kSerializedUnitExtrasStemTrie = nullptr;
+ gUnitExtrasInitOnce.reset();
+ return TRUE;
+}
+
+void U_CALLCONV initUnitExtras(UErrorCode& status) {
+ ucln_i18n_registerCleanup(UCLN_I18N_UNIT_EXTRAS, cleanupUnitExtras);
+
+ UCharsTrieBuilder b(status);
+ if (U_FAILURE(status)) { return; }
+
+ // Add SI prefixes
+ for (const auto& siPrefixInfo : gSIPrefixStrings) {
+ UnicodeString uSIPrefix(siPrefixInfo.string, -1, US_INV);
+ b.add(uSIPrefix, siPrefixInfo.value + kSIPrefixOffset, status);
+ }
+ if (U_FAILURE(status)) { return; }
+
+ // Add syntax parts (compound, power prefixes)
+ b.add(u"-per-", COMPOUND_PART_PER, status);
+ b.add(u"-", COMPOUND_PART_TIMES, status);
+ b.add(u"-and-", COMPOUND_PART_AND, status);
+ b.add(u"per-", INITIAL_COMPOUND_PART_PER, status);
+ b.add(u"square-", POWER_PART_P2, status);
+ b.add(u"cubic-", POWER_PART_P3, status);
+ b.add(u"p2-", POWER_PART_P2, status);
+ b.add(u"p3-", POWER_PART_P3, status);
+ b.add(u"p4-", POWER_PART_P4, status);
+ b.add(u"p5-", POWER_PART_P5, status);
+ b.add(u"p6-", POWER_PART_P6, status);
+ b.add(u"p7-", POWER_PART_P7, status);
+ b.add(u"p8-", POWER_PART_P8, status);
+ b.add(u"p9-", POWER_PART_P9, status);
+ b.add(u"p10-", POWER_PART_P10, status);
+ b.add(u"p11-", POWER_PART_P11, status);
+ b.add(u"p12-", POWER_PART_P12, status);
+ b.add(u"p13-", POWER_PART_P13, status);
+ b.add(u"p14-", POWER_PART_P14, status);
+ b.add(u"p15-", POWER_PART_P15, status);
+ if (U_FAILURE(status)) { return; }
+
+ // Add sanctioned simple units by offset
+ int32_t simpleUnitOffset = kSimpleUnitOffset;
+ for (auto simpleUnit : gSimpleUnits) {
+ b.add(simpleUnit, simpleUnitOffset++, status);
+ }
+
+ // 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);
+ kSerializedUnitExtrasStemTrie = static_cast<char16_t*>(uprv_malloc(numBytes));
+ uprv_memcpy(kSerializedUnitExtrasStemTrie, result.getBuffer(), numBytes);
+}
+
+class Token {
+public:
+ Token(int32_t match) : fMatch(match) {}
+
+ enum Type {
+ TYPE_UNDEFINED,
+ TYPE_SI_PREFIX,
+ // Token type for "-per-", "-", and "-and-".
+ TYPE_COMPOUND_PART,
+ // Token type for "per-".
+ TYPE_INITIAL_COMPOUND_PART,
+ TYPE_POWER_PART,
+ TYPE_SIMPLE_UNIT,
+ };
+
+ // Calling getType() is invalid, resulting in an assertion failure, if Token
+ // value isn't positive.
+ Type getType() const {
+ U_ASSERT(fMatch > 0);
+ if (fMatch < kCompoundPartOffset) {
+ return TYPE_SI_PREFIX;
+ }
+ if (fMatch < kInitialCompoundPartOffset) {
+ return TYPE_COMPOUND_PART;
+ }
+ if (fMatch < kPowerPartOffset) {
+ return TYPE_INITIAL_COMPOUND_PART;
+ }
+ if (fMatch < kSimpleUnitOffset) {
+ return TYPE_POWER_PART;
+ }
+ return TYPE_SIMPLE_UNIT;
+ }
+
+ UMeasureSIPrefix getSIPrefix() const {
+ U_ASSERT(getType() == TYPE_SI_PREFIX);
+ return static_cast<UMeasureSIPrefix>(fMatch - kSIPrefixOffset);
+ }
+
+ // Valid only for tokens with type TYPE_COMPOUND_PART.
+ int32_t getMatch() const {
+ U_ASSERT(getType() == TYPE_COMPOUND_PART);
+ return fMatch;
+ }
+
+ int32_t getInitialCompoundPart() const {
+ // Even if there is only one InitialCompoundPart value, we have this
+ // function for the simplicity of code consistency.
+ U_ASSERT(getType() == TYPE_INITIAL_COMPOUND_PART);
+ // Defensive: if this assert fails, code using this function also needs
+ // to change.
+ U_ASSERT(fMatch == INITIAL_COMPOUND_PART_PER);
+ return fMatch;
+ }
+
+ int8_t getPower() const {
+ U_ASSERT(getType() == TYPE_POWER_PART);
+ return static_cast<int8_t>(fMatch - kPowerPartOffset);
+ }
+
+ int32_t getSimpleUnitIndex() const {
+ U_ASSERT(getType() == TYPE_SIMPLE_UNIT);
+ return fMatch - kSimpleUnitOffset;
+ }
+
+private:
+ int32_t fMatch;
+};
+
+class Parser {
+public:
+ /**
+ * Factory function for parsing the given identifier.
+ *
+ * @param source The identifier to parse. This function does not make a copy
+ * of source: the underlying string that source points at, must outlive the
+ * parser.
+ * @param status ICU error code.
+ */
+ static Parser from(StringPiece source, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return Parser();
+ }
+ umtx_initOnce(gUnitExtrasInitOnce, &initUnitExtras, status);
+ if (U_FAILURE(status)) {
+ return Parser();
+ }
+ return Parser(source);
+ }
+
+ MeasureUnitImpl parse(UErrorCode& status) {
+ MeasureUnitImpl result;
+ parseImpl(result, status);
+ return result;
+ }
+
+private:
+ // Tracks parser progress: the offset into fSource.
+ int32_t fIndex = 0;
+
+ // Since we're not owning this memory, whatever is passed to the constructor
+ // should live longer than this Parser - and the parser shouldn't return any
+ // references to that string.
+ StringPiece fSource;
+ UCharsTrie fTrie;
+
+ // Set to true when we've seen a "-per-" or a "per-", after which all units
+ // are in the denominator. Until we find an "-and-", at which point the
+ // identifier is invalid pending TODO(CLDR-13700).
+ bool fAfterPer = false;
+
+ Parser() : fSource(""), fTrie(u"") {}
+
+ Parser(StringPiece source)
+ : fSource(source), fTrie(kSerializedUnitExtrasStemTrie) {}
+
+ inline bool hasNext() const {
+ return fIndex < fSource.length();
+ }
+
+ // Returns the next Token parsed from fSource, advancing fIndex to the end
+ // of that token in fSource. In case of U_FAILURE(status), the token
+ // returned will cause an abort if getType() is called on it.
+ Token nextToken(UErrorCode& status) {
+ fTrie.reset();
+ int32_t match = -1;
+ // Saves the position in the fSource string for the end of the most
+ // recent matching token.
+ int32_t previ = -1;
+ // Find the longest token that matches a value in the trie:
+ while (fIndex < fSource.length()) {
+ auto result = fTrie.next(fSource.data()[fIndex++]);
+ if (result == USTRINGTRIE_NO_MATCH) {
+ break;
+ } else if (result == USTRINGTRIE_NO_VALUE) {
+ continue;
+ }
+ U_ASSERT(USTRINGTRIE_HAS_VALUE(result));
+ match = fTrie.getValue();
+ previ = fIndex;
+ if (result == USTRINGTRIE_FINAL_VALUE) {
+ break;
+ }
+ U_ASSERT(result == USTRINGTRIE_INTERMEDIATE_VALUE);
+ // continue;
+ }
+
+ if (match < 0) {
+ status = kUnitIdentifierSyntaxError;
+ } else {
+ fIndex = previ;
+ }
+ return Token(match);
+ }
+
+ /**
+ * Returns the next "single unit" via result.
+ *
+ * If a "-per-" was parsed, the result will have appropriate negative
+ * dimensionality.
+ *
+ * Returns an error if we parse both compound units and "-and-", since mixed
+ * compound units are not yet supported - TODO(CLDR-13700).
+ *
+ * @param result Will be overwritten by the result, if status shows success.
+ * @param sawAnd If an "-and-" was parsed prior to finding the "single
+ * unit", sawAnd is set to true. If not, it is left as is.
+ * @param status ICU error code.
+ */
+ void nextSingleUnit(SingleUnitImpl& result, bool& sawAnd, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // state:
+ // 0 = no tokens seen yet (will accept power, SI prefix, or simple unit)
+ // 1 = power token seen (will not accept another power token)
+ // 2 = SI prefix token seen (will not accept a power or SI prefix token)
+ int32_t state = 0;
+
+ bool atStart = fIndex == 0;
+ Token token = nextToken(status);
+ if (U_FAILURE(status)) { return; }
+
+ if (atStart) {
+ // Identifiers optionally start with "per-".
+ if (token.getType() == Token::TYPE_INITIAL_COMPOUND_PART) {
+ U_ASSERT(token.getInitialCompoundPart() == INITIAL_COMPOUND_PART_PER);
+ fAfterPer = true;
+ result.dimensionality = -1;
+
+ token = nextToken(status);
+ if (U_FAILURE(status)) { return; }
+ }
+ } else {
+ // All other SingleUnit's are separated from previous SingleUnit's
+ // via a compound part:
+ if (token.getType() != Token::TYPE_COMPOUND_PART) {
+ status = kUnitIdentifierSyntaxError;
+ return;
+ }
+
+ switch (token.getMatch()) {
+ case COMPOUND_PART_PER:
+ if (sawAnd) {
+ // Mixed compound units not yet supported,
+ // TODO(CLDR-13700).
+ status = kUnitIdentifierSyntaxError;
+ return;
+ }
+ fAfterPer = true;
+ result.dimensionality = -1;
+ break;
+
+ case COMPOUND_PART_TIMES:
+ if (fAfterPer) {
+ result.dimensionality = -1;
+ }
+ break;
+
+ case COMPOUND_PART_AND:
+ if (fAfterPer) {
+ // Can't start with "-and-", and mixed compound units
+ // not yet supported, TODO(CLDR-13700).
+ status = kUnitIdentifierSyntaxError;
+ return;
+ }
+ sawAnd = true;
+ break;
+ }
+
+ token = nextToken(status);
+ if (U_FAILURE(status)) { return; }
+ }
+
+ // Read tokens until we have a complete SingleUnit or we reach the end.
+ while (true) {
+ switch (token.getType()) {
+ case Token::TYPE_POWER_PART:
+ if (state > 0) {
+ status = kUnitIdentifierSyntaxError;
+ return;
+ }
+ result.dimensionality *= token.getPower();
+ state = 1;
+ break;
+
+ case Token::TYPE_SI_PREFIX:
+ if (state > 1) {
+ status = kUnitIdentifierSyntaxError;
+ return;
+ }
+ result.siPrefix = token.getSIPrefix();
+ state = 2;
+ break;
+
+ case Token::TYPE_SIMPLE_UNIT:
+ result.index = token.getSimpleUnitIndex();
+ return;
+
+ default:
+ status = kUnitIdentifierSyntaxError;
+ return;
+ }
+
+ if (!hasNext()) {
+ // We ran out of tokens before finding a complete single unit.
+ status = kUnitIdentifierSyntaxError;
+ return;
+ }
+ token = nextToken(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ }
+ }
+
+ /// @param result is modified, not overridden. Caller must pass in a
+ /// default-constructed (empty) MeasureUnitImpl instance.
+ void parseImpl(MeasureUnitImpl& result, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (fSource.empty()) {
+ // The dimenionless unit: nothing to parse. leave result as is.
+ return;
+ }
+ int32_t unitNum = 0;
+ while (hasNext()) {
+ bool sawAnd = false;
+ SingleUnitImpl singleUnit;
+ nextSingleUnit(singleUnit, sawAnd, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ U_ASSERT(!singleUnit.isDimensionless());
+ bool added = result.append(singleUnit, status);
+ if (sawAnd && !added) {
+ // Two similar units are not allowed in a mixed unit
+ status = kUnitIdentifierSyntaxError;
+ return;
+ }
+ if ((++unitNum) >= 2) {
+ // nextSingleUnit fails appropriately for "per" and "and" in the
+ // same identifier. It doesn't fail for other compound units
+ // (COMPOUND_PART_TIMES). Consequently we take care of that
+ // here.
+ UMeasureUnitComplexity complexity =
+ sawAnd ? UMEASURE_UNIT_MIXED : UMEASURE_UNIT_COMPOUND;
+ if (unitNum == 2) {
+ U_ASSERT(result.complexity == UMEASURE_UNIT_SINGLE);
+ result.complexity = complexity;
+ } else if (result.complexity != complexity) {
+ // Can't have mixed compound units
+ status = kUnitIdentifierSyntaxError;
+ return;
+ }
+ }
+ }
+ }
+};
+
+int32_t U_CALLCONV
+compareSingleUnits(const void* /*context*/, const void* left, const void* right) {
+ auto realLeft = static_cast<const SingleUnitImpl* const*>(left);
+ auto realRight = static_cast<const SingleUnitImpl* const*>(right);
+ return (*realLeft)->compareTo(**realRight);
+}
+
+/**
+ * Generate the identifier string for a single unit in place.
+ *
+ * Does not support the dimensionless SingleUnitImpl: calling serializeSingle
+ * with the dimensionless unit results in an U_INTERNAL_PROGRAM_ERROR.
+ *
+ * @param first If singleUnit is part of a compound unit, and not its first
+ * single unit, set this to false. Otherwise: set to true.
+ */
+void serializeSingle(const SingleUnitImpl& singleUnit, bool first, CharString& output, UErrorCode& status) {
+ if (first && singleUnit.dimensionality < 0) {
+ // Essentially the "unary per". For compound units with a numerator, the
+ // caller takes care of the "binary per".
+ output.append("per-", status);
+ }
+
+ if (singleUnit.isDimensionless()) {
+ status = U_INTERNAL_PROGRAM_ERROR;
+ return;
+ }
+ int8_t posPower = std::abs(singleUnit.dimensionality);
+ if (posPower == 0) {
+ status = U_INTERNAL_PROGRAM_ERROR;
+ } else if (posPower == 1) {
+ // no-op
+ } else if (posPower == 2) {
+ output.append("square-", status);
+ } else if (posPower == 3) {
+ output.append("cubic-", status);
+ } else if (posPower < 10) {
+ output.append('p', status);
+ output.append(posPower + '0', status);
+ output.append('-', status);
+ } else if (posPower <= 15) {
+ output.append("p1", status);
+ output.append('0' + (posPower % 10), status);
+ output.append('-', status);
+ } else {
+ status = kUnitIdentifierSyntaxError;
+ }
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ if (singleUnit.siPrefix != UMEASURE_SI_PREFIX_ONE) {
+ for (const auto& siPrefixInfo : gSIPrefixStrings) {
+ if (siPrefixInfo.value == singleUnit.siPrefix) {
+ output.append(siPrefixInfo.string, status);
+ break;
+ }
+ }
+ }
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ output.appendInvariantChars(gSimpleUnits[singleUnit.index], status);
+}
+
+/**
+ * Normalize a MeasureUnitImpl and generate the identifier string in place.
+ */
+void serialize(MeasureUnitImpl& impl, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ U_ASSERT(impl.identifier.isEmpty());
+ if (impl.units.length() == 0) {
+ // Dimensionless, constructed by the default constructor: no appending
+ // to impl.identifier, we wish it to contain the zero-length string.
+ return;
+ }
+ if (impl.complexity == UMEASURE_UNIT_COMPOUND) {
+ // Note: don't sort a MIXED unit
+ uprv_sortArray(
+ impl.units.getAlias(),
+ impl.units.length(),
+ sizeof(impl.units[0]),
+ compareSingleUnits,
+ nullptr,
+ false,
+ &status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ }
+ serializeSingle(*impl.units[0], true, impl.identifier, status);
+ if (impl.units.length() == 1) {
+ return;
+ }
+ for (int32_t i = 1; i < impl.units.length(); i++) {
+ const SingleUnitImpl& prev = *impl.units[i-1];
+ const SingleUnitImpl& curr = *impl.units[i];
+ if (impl.complexity == UMEASURE_UNIT_MIXED) {
+ impl.identifier.append("-and-", status);
+ serializeSingle(curr, true, impl.identifier, status);
+ } else {
+ if (prev.dimensionality > 0 && curr.dimensionality < 0) {
+ impl.identifier.append("-per-", status);
+ } else {
+ impl.identifier.append('-', status);
+ }
+ serializeSingle(curr, false, impl.identifier, status);
+ }
+ }
+
+}
+
+/**
+ * Appends a SingleUnitImpl to a MeasureUnitImpl.
+ *
+ * @return true if a new item was added. If unit is the dimensionless unit, it
+ * is never added: the return value will always be false.
+ */
+bool appendImpl(MeasureUnitImpl& impl, const SingleUnitImpl& unit, UErrorCode& status) {
+ if (unit.isDimensionless()) {
+ // We don't append dimensionless units.
+ return false;
+ }
+ // Find a similar unit that already exists, to attempt to coalesce
+ SingleUnitImpl* oldUnit = nullptr;
+ for (int32_t i = 0; i < impl.units.length(); i++) {
+ auto* candidate = impl.units[i];
+ if (candidate->isCompatibleWith(unit)) {
+ oldUnit = candidate;
+ }
+ }
+ if (oldUnit) {
+ // Both dimensionalities will be positive, or both will be negative, by
+ // virtue of isCompatibleWith().
+ oldUnit->dimensionality += unit.dimensionality;
+ } else {
+ SingleUnitImpl* destination = impl.units.emplaceBack();
+ if (!destination) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ *destination = unit;
+ }
+ return (oldUnit == nullptr);
+}
+
+} // namespace
+
+
+SingleUnitImpl SingleUnitImpl::forMeasureUnit(const MeasureUnit& measureUnit, UErrorCode& status) {
+ MeasureUnitImpl temp;
+ const MeasureUnitImpl& impl = MeasureUnitImpl::forMeasureUnit(measureUnit, temp, status);
+ if (U_FAILURE(status)) {
+ return {};
+ }
+ if (impl.units.length() == 0) {
+ return {};
+ }
+ if (impl.units.length() == 1) {
+ return *impl.units[0];
+ }
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return {};
+}
+
+MeasureUnit SingleUnitImpl::build(UErrorCode& status) const {
+ MeasureUnitImpl temp;
+ temp.append(*this, status);
+ return std::move(temp).build(status);
+}
+
+
+MeasureUnitImpl MeasureUnitImpl::forIdentifier(StringPiece identifier, UErrorCode& status) {
+ return Parser::from(identifier, status).parse(status);
+}
+
+const MeasureUnitImpl& MeasureUnitImpl::forMeasureUnit(
+ const MeasureUnit& measureUnit, MeasureUnitImpl& memory, UErrorCode& status) {
+ if (measureUnit.fImpl) {
+ return *measureUnit.fImpl;
+ } else {
+ memory = Parser::from(measureUnit.getIdentifier(), status).parse(status);
+ return memory;
+ }
+}
+
+MeasureUnitImpl MeasureUnitImpl::forMeasureUnitMaybeCopy(
+ const MeasureUnit& measureUnit, UErrorCode& status) {
+ if (measureUnit.fImpl) {
+ return measureUnit.fImpl->copy(status);
+ } else {
+ return Parser::from(measureUnit.getIdentifier(), status).parse(status);
+ }
+}
+
+void MeasureUnitImpl::takeReciprocal(UErrorCode& /*status*/) {
+ identifier.clear();
+ for (int32_t i = 0; i < units.length(); i++) {
+ units[i]->dimensionality *= -1;
+ }
+}
+
+bool MeasureUnitImpl::append(const SingleUnitImpl& singleUnit, UErrorCode& status) {
+ identifier.clear();
+ return appendImpl(*this, singleUnit, status);
+}
+
+MeasureUnit MeasureUnitImpl::build(UErrorCode& status) && {
+ serialize(*this, status);
+ return MeasureUnit(std::move(*this));
+}
+
+
+MeasureUnit MeasureUnit::forIdentifier(StringPiece identifier, UErrorCode& status) {
+ return Parser::from(identifier, status).parse(status).build(status);
+}
+
+UMeasureUnitComplexity MeasureUnit::getComplexity(UErrorCode& status) const {
+ MeasureUnitImpl temp;
+ return MeasureUnitImpl::forMeasureUnit(*this, temp, status).complexity;
+}
+
+UMeasureSIPrefix MeasureUnit::getSIPrefix(UErrorCode& status) const {
+ return SingleUnitImpl::forMeasureUnit(*this, status).siPrefix;
+}
+
+MeasureUnit MeasureUnit::withSIPrefix(UMeasureSIPrefix prefix, UErrorCode& status) const {
+ SingleUnitImpl singleUnit = SingleUnitImpl::forMeasureUnit(*this, status);
+ singleUnit.siPrefix = prefix;
+ return singleUnit.build(status);
+}
+
+int32_t MeasureUnit::getDimensionality(UErrorCode& status) const {
+ SingleUnitImpl singleUnit = SingleUnitImpl::forMeasureUnit(*this, status);
+ if (U_FAILURE(status)) { return 0; }
+ if (singleUnit.isDimensionless()) {
+ return 0;
+ }
+ return singleUnit.dimensionality;
+}
+
+MeasureUnit MeasureUnit::withDimensionality(int32_t dimensionality, UErrorCode& status) const {
+ SingleUnitImpl singleUnit = SingleUnitImpl::forMeasureUnit(*this, status);
+ singleUnit.dimensionality = dimensionality;
+ return singleUnit.build(status);
+}
+
+MeasureUnit MeasureUnit::reciprocal(UErrorCode& status) const {
+ MeasureUnitImpl impl = MeasureUnitImpl::forMeasureUnitMaybeCopy(*this, status);
+ impl.takeReciprocal(status);
+ return std::move(impl).build(status);
+}
+
+MeasureUnit MeasureUnit::product(const MeasureUnit& other, UErrorCode& status) const {
+ MeasureUnitImpl impl = MeasureUnitImpl::forMeasureUnitMaybeCopy(*this, status);
+ MeasureUnitImpl temp;
+ const MeasureUnitImpl& otherImpl = MeasureUnitImpl::forMeasureUnit(other, temp, status);
+ if (impl.complexity == UMEASURE_UNIT_MIXED || otherImpl.complexity == UMEASURE_UNIT_MIXED) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return {};
+ }
+ for (int32_t i = 0; i < otherImpl.units.length(); i++) {
+ impl.append(*otherImpl.units[i], status);
+ }
+ if (impl.units.length() > 1) {
+ impl.complexity = UMEASURE_UNIT_COMPOUND;
+ }
+ return std::move(impl).build(status);
+}
+
+LocalArray<MeasureUnit> MeasureUnit::splitToSingleUnits(int32_t& outCount, UErrorCode& status) const {
+ MeasureUnitImpl temp;
+ const MeasureUnitImpl& impl = MeasureUnitImpl::forMeasureUnit(*this, temp, status);
+ outCount = impl.units.length();
+ MeasureUnit* arr = new MeasureUnit[outCount];
+ for (int32_t i = 0; i < outCount; i++) {
+ arr[i] = impl.units[i]->build(status);
+ }
+ return LocalArray<MeasureUnit>(arr, status);
+}
+
+
+U_NAMESPACE_END
+
+#endif /* !UNCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/measunit_impl.h b/contrib/libs/icu/i18n/measunit_impl.h
index c69d243b3b..6aa33d740b 100644
--- a/contrib/libs/icu/i18n/measunit_impl.h
+++ b/contrib/libs/icu/i18n/measunit_impl.h
@@ -1,213 +1,213 @@
-// © 2020 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html
-
-#ifndef __MEASUNIT_IMPL_H__
-#define __MEASUNIT_IMPL_H__
-
-#include "unicode/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/measunit.h"
-#include "cmemory.h"
-#include "charstr.h"
-
-U_NAMESPACE_BEGIN
-
-
-static const char16_t kDefaultCurrency[] = u"XXX";
-static const char kDefaultCurrency8[] = "XXX";
-
-
-/**
- * A struct representing a single unit (optional SI prefix and dimensionality).
- */
-struct SingleUnitImpl : public UMemory {
- /**
- * Gets a single unit from the MeasureUnit. If there are multiple single units, sets an error
- * code and returns the base dimensionless unit. Parses if necessary.
- */
- static SingleUnitImpl forMeasureUnit(const MeasureUnit& measureUnit, UErrorCode& status);
-
- /** Transform this SingleUnitImpl into a MeasureUnit, simplifying if possible. */
- MeasureUnit build(UErrorCode& status) const;
-
- /**
- * Compare this SingleUnitImpl to another SingleUnitImpl for the sake of
- * sorting and coalescing.
- *
- * Takes the sign of dimensionality into account, but not the absolute
- * value: per-meter is not considered the same as meter, but meter is
- * considered the same as square-meter.
- *
- * The dimensionless unit generally does not get compared, but if it did, it
- * would sort before other units by virtue of index being < 0 and
- * dimensionality not being negative.
- */
- int32_t compareTo(const SingleUnitImpl& other) const {
- if (dimensionality < 0 && other.dimensionality > 0) {
- // Positive dimensions first
- return 1;
- }
- if (dimensionality > 0 && other.dimensionality < 0) {
- return -1;
- }
- if (index < other.index) {
- return -1;
- }
- if (index > other.index) {
- return 1;
- }
- if (siPrefix < other.siPrefix) {
- return -1;
- }
- if (siPrefix > other.siPrefix) {
- return 1;
- }
- return 0;
- }
-
- /**
- * Return whether this SingleUnitImpl is compatible with another for the purpose of coalescing.
- *
- * Units with the same base unit and SI prefix should match, except that they must also have
- * the same dimensionality sign, such that we don't merge numerator and denominator.
- */
- bool isCompatibleWith(const SingleUnitImpl& other) const {
- return (compareTo(other) == 0);
- }
-
- /**
- * Returns true if this unit is the "dimensionless base unit", as produced
- * by the MeasureUnit() default constructor. (This does not include the
- * likes of concentrations or angles.)
- */
- bool isDimensionless() const {
- return index == -1;
- }
-
- /**
- * Simple unit index, unique for every simple unit, -1 for the dimensionless
- * unit. This is an index into a string list in measunit_extra.cpp.
- *
- * The default value is -1, meaning the dimensionless unit:
- * isDimensionless() will return true, until index is changed.
- */
- int32_t index = -1;
-
- /**
- * SI prefix.
- *
- * This is ignored for the dimensionless unit.
- */
- UMeasureSIPrefix siPrefix = UMEASURE_SI_PREFIX_ONE;
-
- /**
- * Dimensionality.
- *
- * This is meaningless for the dimensionless unit.
- */
- int32_t dimensionality = 1;
-};
-
-
-/**
- * Internal representation of measurement units. Capable of representing all complexities of units,
- * including mixed and compound units.
- */
-struct MeasureUnitImpl : public UMemory {
- /** Extract the MeasureUnitImpl from a MeasureUnit. */
- static inline const MeasureUnitImpl* get(const MeasureUnit& measureUnit) {
- return measureUnit.fImpl;
- }
-
- /**
- * Parse a unit identifier into a MeasureUnitImpl.
- *
- * @param identifier The unit identifier string.
- * @param status Set if the identifier string is not valid.
- * @return A newly parsed value object. Behaviour of this unit is
- * unspecified if an error is returned via status.
- */
- static MeasureUnitImpl forIdentifier(StringPiece identifier, UErrorCode& status);
-
- /**
- * Extract the MeasureUnitImpl from a MeasureUnit, or parse if it is not present.
+// © 2020 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#ifndef __MEASUNIT_IMPL_H__
+#define __MEASUNIT_IMPL_H__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/measunit.h"
+#include "cmemory.h"
+#include "charstr.h"
+
+U_NAMESPACE_BEGIN
+
+
+static const char16_t kDefaultCurrency[] = u"XXX";
+static const char kDefaultCurrency8[] = "XXX";
+
+
+/**
+ * A struct representing a single unit (optional SI prefix and dimensionality).
+ */
+struct SingleUnitImpl : public UMemory {
+ /**
+ * Gets a single unit from the MeasureUnit. If there are multiple single units, sets an error
+ * code and returns the base dimensionless unit. Parses if necessary.
+ */
+ static SingleUnitImpl forMeasureUnit(const MeasureUnit& measureUnit, UErrorCode& status);
+
+ /** Transform this SingleUnitImpl into a MeasureUnit, simplifying if possible. */
+ MeasureUnit build(UErrorCode& status) const;
+
+ /**
+ * Compare this SingleUnitImpl to another SingleUnitImpl for the sake of
+ * sorting and coalescing.
*
- * @param measureUnit The source MeasureUnit.
- * @param memory A place to write the new MeasureUnitImpl if parsing is required.
- * @param status Set if an error occurs.
- * @return A reference to either measureUnit.fImpl or memory.
- */
- static const MeasureUnitImpl& forMeasureUnit(
- const MeasureUnit& measureUnit, MeasureUnitImpl& memory, UErrorCode& status);
-
- /**
- * Extract the MeasureUnitImpl from a MeasureUnit, or parse if it is not present.
- *
- * @param measureUnit The source MeasureUnit.
- * @param status Set if an error occurs.
- * @return A value object, either newly parsed or copied from measureUnit.
- */
- static MeasureUnitImpl forMeasureUnitMaybeCopy(
- const MeasureUnit& measureUnit, UErrorCode& status);
-
- /**
- * Used for currency units.
- */
- static inline MeasureUnitImpl forCurrencyCode(StringPiece currencyCode) {
- MeasureUnitImpl result;
- UErrorCode localStatus = U_ZERO_ERROR;
- result.identifier.append(currencyCode, localStatus);
- // localStatus is not expected to fail since currencyCode should be 3 chars long
- return result;
- }
-
- /** Transform this MeasureUnitImpl into a MeasureUnit, simplifying if possible. */
- MeasureUnit build(UErrorCode& status) &&;
-
- /**
- * Create a copy of this MeasureUnitImpl. Don't use copy constructor to make this explicit.
- */
- inline MeasureUnitImpl copy(UErrorCode& status) const {
- MeasureUnitImpl result;
- result.complexity = complexity;
- result.units.appendAll(units, status);
- result.identifier.append(identifier, status);
- return result;
- }
-
- /** Mutates this MeasureUnitImpl to take the reciprocal. */
- void takeReciprocal(UErrorCode& status);
-
- /**
- * Mutates this MeasureUnitImpl to append a single unit.
- *
- * @return true if a new item was added. If unit is the dimensionless unit,
- * it is never added: the return value will always be false.
- */
- bool append(const SingleUnitImpl& singleUnit, UErrorCode& status);
-
- /** The complexity, either SINGLE, COMPOUND, or MIXED. */
- UMeasureUnitComplexity complexity = UMEASURE_UNIT_SINGLE;
-
- /**
- * The list of simple units. These may be summed or multiplied, based on the
- * value of the complexity field.
- *
- * The "dimensionless" unit (SingleUnitImpl default constructor) must not be
- * added to this list.
- */
- MaybeStackVector<SingleUnitImpl> units;
-
- /**
- * The full unit identifier. Owned by the MeasureUnitImpl. Empty if not computed.
- */
- CharString identifier;
-};
-
-
-U_NAMESPACE_END
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
-#endif //__MEASUNIT_IMPL_H__
+ * Takes the sign of dimensionality into account, but not the absolute
+ * value: per-meter is not considered the same as meter, but meter is
+ * considered the same as square-meter.
+ *
+ * The dimensionless unit generally does not get compared, but if it did, it
+ * would sort before other units by virtue of index being < 0 and
+ * dimensionality not being negative.
+ */
+ int32_t compareTo(const SingleUnitImpl& other) const {
+ if (dimensionality < 0 && other.dimensionality > 0) {
+ // Positive dimensions first
+ return 1;
+ }
+ if (dimensionality > 0 && other.dimensionality < 0) {
+ return -1;
+ }
+ if (index < other.index) {
+ return -1;
+ }
+ if (index > other.index) {
+ return 1;
+ }
+ if (siPrefix < other.siPrefix) {
+ return -1;
+ }
+ if (siPrefix > other.siPrefix) {
+ return 1;
+ }
+ return 0;
+ }
+
+ /**
+ * Return whether this SingleUnitImpl is compatible with another for the purpose of coalescing.
+ *
+ * Units with the same base unit and SI prefix should match, except that they must also have
+ * the same dimensionality sign, such that we don't merge numerator and denominator.
+ */
+ bool isCompatibleWith(const SingleUnitImpl& other) const {
+ return (compareTo(other) == 0);
+ }
+
+ /**
+ * Returns true if this unit is the "dimensionless base unit", as produced
+ * by the MeasureUnit() default constructor. (This does not include the
+ * likes of concentrations or angles.)
+ */
+ bool isDimensionless() const {
+ return index == -1;
+ }
+
+ /**
+ * Simple unit index, unique for every simple unit, -1 for the dimensionless
+ * unit. This is an index into a string list in measunit_extra.cpp.
+ *
+ * The default value is -1, meaning the dimensionless unit:
+ * isDimensionless() will return true, until index is changed.
+ */
+ int32_t index = -1;
+
+ /**
+ * SI prefix.
+ *
+ * This is ignored for the dimensionless unit.
+ */
+ UMeasureSIPrefix siPrefix = UMEASURE_SI_PREFIX_ONE;
+
+ /**
+ * Dimensionality.
+ *
+ * This is meaningless for the dimensionless unit.
+ */
+ int32_t dimensionality = 1;
+};
+
+
+/**
+ * Internal representation of measurement units. Capable of representing all complexities of units,
+ * including mixed and compound units.
+ */
+struct MeasureUnitImpl : public UMemory {
+ /** Extract the MeasureUnitImpl from a MeasureUnit. */
+ static inline const MeasureUnitImpl* get(const MeasureUnit& measureUnit) {
+ return measureUnit.fImpl;
+ }
+
+ /**
+ * Parse a unit identifier into a MeasureUnitImpl.
+ *
+ * @param identifier The unit identifier string.
+ * @param status Set if the identifier string is not valid.
+ * @return A newly parsed value object. Behaviour of this unit is
+ * unspecified if an error is returned via status.
+ */
+ static MeasureUnitImpl forIdentifier(StringPiece identifier, UErrorCode& status);
+
+ /**
+ * Extract the MeasureUnitImpl from a MeasureUnit, or parse if it is not present.
+ *
+ * @param measureUnit The source MeasureUnit.
+ * @param memory A place to write the new MeasureUnitImpl if parsing is required.
+ * @param status Set if an error occurs.
+ * @return A reference to either measureUnit.fImpl or memory.
+ */
+ static const MeasureUnitImpl& forMeasureUnit(
+ const MeasureUnit& measureUnit, MeasureUnitImpl& memory, UErrorCode& status);
+
+ /**
+ * Extract the MeasureUnitImpl from a MeasureUnit, or parse if it is not present.
+ *
+ * @param measureUnit The source MeasureUnit.
+ * @param status Set if an error occurs.
+ * @return A value object, either newly parsed or copied from measureUnit.
+ */
+ static MeasureUnitImpl forMeasureUnitMaybeCopy(
+ const MeasureUnit& measureUnit, UErrorCode& status);
+
+ /**
+ * Used for currency units.
+ */
+ static inline MeasureUnitImpl forCurrencyCode(StringPiece currencyCode) {
+ MeasureUnitImpl result;
+ UErrorCode localStatus = U_ZERO_ERROR;
+ result.identifier.append(currencyCode, localStatus);
+ // localStatus is not expected to fail since currencyCode should be 3 chars long
+ return result;
+ }
+
+ /** Transform this MeasureUnitImpl into a MeasureUnit, simplifying if possible. */
+ MeasureUnit build(UErrorCode& status) &&;
+
+ /**
+ * Create a copy of this MeasureUnitImpl. Don't use copy constructor to make this explicit.
+ */
+ inline MeasureUnitImpl copy(UErrorCode& status) const {
+ MeasureUnitImpl result;
+ result.complexity = complexity;
+ result.units.appendAll(units, status);
+ result.identifier.append(identifier, status);
+ return result;
+ }
+
+ /** Mutates this MeasureUnitImpl to take the reciprocal. */
+ void takeReciprocal(UErrorCode& status);
+
+ /**
+ * Mutates this MeasureUnitImpl to append a single unit.
+ *
+ * @return true if a new item was added. If unit is the dimensionless unit,
+ * it is never added: the return value will always be false.
+ */
+ bool append(const SingleUnitImpl& singleUnit, UErrorCode& status);
+
+ /** The complexity, either SINGLE, COMPOUND, or MIXED. */
+ UMeasureUnitComplexity complexity = UMEASURE_UNIT_SINGLE;
+
+ /**
+ * The list of simple units. These may be summed or multiplied, based on the
+ * value of the complexity field.
+ *
+ * The "dimensionless" unit (SingleUnitImpl default constructor) must not be
+ * added to this list.
+ */
+ MaybeStackVector<SingleUnitImpl> units;
+
+ /**
+ * The full unit identifier. Owned by the MeasureUnitImpl. Empty if not computed.
+ */
+ CharString identifier;
+};
+
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+#endif //__MEASUNIT_IMPL_H__
diff --git a/contrib/libs/icu/i18n/measure.cpp b/contrib/libs/icu/i18n/measure.cpp
index bffa44215e..53f585fe1b 100644
--- a/contrib/libs/icu/i18n/measure.cpp
+++ b/contrib/libs/icu/i18n/measure.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -43,12 +43,12 @@ Measure& Measure::operator=(const Measure& other) {
if (this != &other) {
delete unit;
number = other.number;
- unit = other.unit->clone();
+ unit = other.unit->clone();
}
return *this;
}
-Measure *Measure::clone() const {
+Measure *Measure::clone() const {
return new Measure(*this);
}
diff --git a/contrib/libs/icu/i18n/msgfmt.cpp b/contrib/libs/icu/i18n/msgfmt.cpp
index 3ca368ef95..b81006129f 100644
--- a/contrib/libs/icu/i18n/msgfmt.cpp
+++ b/contrib/libs/icu/i18n/msgfmt.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/********************************************************************
* COPYRIGHT:
@@ -31,7 +31,7 @@
#include "unicode/decimfmt.h"
#include "unicode/localpointer.h"
#include "unicode/msgfmt.h"
-#include "unicode/numberformatter.h"
+#include "unicode/numberformatter.h"
#include "unicode/plurfmt.h"
#include "unicode/rbnf.h"
#include "unicode/selfmt.h"
@@ -49,7 +49,7 @@
#include "ustrfmt.h"
#include "util.h"
#include "uvector.h"
-#include "number_decimalquantity.h"
+#include "number_decimalquantity.h"
// *****************************************************************************
// class MessageFormat
@@ -436,7 +436,7 @@ MessageFormat::operator==(const Format& rhs) const
// -------------------------------------
// Creates a copy of this MessageFormat, the caller owns the copy.
-MessageFormat*
+MessageFormat*
MessageFormat::clone() const
{
return new MessageFormat(*this);
@@ -810,31 +810,31 @@ MessageFormat::getFormats(int32_t& cnt) const
// method on this object. We construct and resize an array
// on demand that contains aliases to the subformats[i].format
// pointers.
-
- // Get total required capacity first (it's refreshed on each call).
- int32_t totalCapacity = 0;
- for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0; ++totalCapacity) {}
-
+
+ // Get total required capacity first (it's refreshed on each call).
+ int32_t totalCapacity = 0;
+ for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0; ++totalCapacity) {}
+
MessageFormat* t = const_cast<MessageFormat*> (this);
cnt = 0;
- if (formatAliases == nullptr) {
- t->formatAliasesCapacity = totalCapacity;
+ if (formatAliases == nullptr) {
+ t->formatAliasesCapacity = totalCapacity;
Format** a = (Format**)
uprv_malloc(sizeof(Format*) * formatAliasesCapacity);
- if (a == nullptr) {
+ if (a == nullptr) {
t->formatAliasesCapacity = 0;
- return nullptr;
+ return nullptr;
}
t->formatAliases = a;
- } else if (totalCapacity > formatAliasesCapacity) {
+ } else if (totalCapacity > formatAliasesCapacity) {
Format** a = (Format**)
- uprv_realloc(formatAliases, sizeof(Format*) * totalCapacity);
- if (a == nullptr) {
+ uprv_realloc(formatAliases, sizeof(Format*) * totalCapacity);
+ if (a == nullptr) {
t->formatAliasesCapacity = 0;
- return nullptr;
+ return nullptr;
}
t->formatAliases = a;
- t->formatAliasesCapacity = totalCapacity;
+ t->formatAliasesCapacity = totalCapacity;
}
for (int32_t partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
@@ -1083,7 +1083,7 @@ void MessageFormat::format(int32_t msgStart, const void *plNumber,
// that formats the number without subtracting the offset.
appendTo.formatAndAppend(pluralNumber.formatter, *arg, success);
}
- } else if ((formatter = getCachedFormatter(i -2)) != 0) {
+ } else if ((formatter = getCachedFormatter(i -2)) != 0) {
// Handles all ArgType.SIMPLE, and formatters from setFormat() and its siblings.
if (dynamic_cast<const ChoiceFormat*>(formatter) ||
dynamic_cast<const PluralFormat*>(formatter) ||
@@ -1687,7 +1687,7 @@ Format* MessageFormat::createAppropriateFormat(UnicodeString& type, UnicodeStrin
Format* fmt = NULL;
int32_t typeID, styleID;
DateFormat::EStyle date_style;
- int32_t firstNonSpace;
+ int32_t firstNonSpace;
switch (typeID = findKeyword(type, TYPE_IDS)) {
case 0: // number
@@ -1706,20 +1706,20 @@ Format* MessageFormat::createAppropriateFormat(UnicodeString& type, UnicodeStrin
formattableType = Formattable::kLong;
fmt = createIntegerFormat(fLocale, ec);
break;
- default: // pattern or skeleton
- firstNonSpace = PatternProps::skipWhiteSpace(style, 0);
- if (style.compare(firstNonSpace, 2, u"::", 0, 2) == 0) {
- // Skeleton
- UnicodeString skeleton = style.tempSubString(firstNonSpace + 2);
- fmt = number::NumberFormatter::forSkeleton(skeleton, ec).locale(fLocale).toFormat(ec);
- } else {
- // Pattern
- fmt = NumberFormat::createInstance(fLocale, ec);
- if (fmt) {
- auto* decfmt = dynamic_cast<DecimalFormat*>(fmt);
- if (decfmt != nullptr) {
- decfmt->applyPattern(style, parseError, ec);
- }
+ default: // pattern or skeleton
+ firstNonSpace = PatternProps::skipWhiteSpace(style, 0);
+ if (style.compare(firstNonSpace, 2, u"::", 0, 2) == 0) {
+ // Skeleton
+ UnicodeString skeleton = style.tempSubString(firstNonSpace + 2);
+ fmt = number::NumberFormatter::forSkeleton(skeleton, ec).locale(fLocale).toFormat(ec);
+ } else {
+ // Pattern
+ fmt = NumberFormat::createInstance(fLocale, ec);
+ if (fmt) {
+ auto* decfmt = dynamic_cast<DecimalFormat*>(fmt);
+ if (decfmt != nullptr) {
+ decfmt->applyPattern(style, parseError, ec);
+ }
}
}
break;
@@ -1729,28 +1729,28 @@ Format* MessageFormat::createAppropriateFormat(UnicodeString& type, UnicodeStrin
case 1: // date
case 2: // time
formattableType = Formattable::kDate;
- firstNonSpace = PatternProps::skipWhiteSpace(style, 0);
- if (style.compare(firstNonSpace, 2, u"::", 0, 2) == 0) {
- // Skeleton
- UnicodeString skeleton = style.tempSubString(firstNonSpace + 2);
- fmt = DateFormat::createInstanceForSkeleton(skeleton, fLocale, ec);
+ firstNonSpace = PatternProps::skipWhiteSpace(style, 0);
+ if (style.compare(firstNonSpace, 2, u"::", 0, 2) == 0) {
+ // Skeleton
+ UnicodeString skeleton = style.tempSubString(firstNonSpace + 2);
+ fmt = DateFormat::createInstanceForSkeleton(skeleton, fLocale, ec);
} else {
- // Pattern
- styleID = findKeyword(style, DATE_STYLE_IDS);
- date_style = (styleID >= 0) ? DATE_STYLES[styleID] : DateFormat::kDefault;
-
- if (typeID == 1) {
- fmt = DateFormat::createDateInstance(date_style, fLocale);
- } else {
- fmt = DateFormat::createTimeInstance(date_style, fLocale);
- }
-
- if (styleID < 0 && fmt != NULL) {
- SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(fmt);
- if (sdtfmt != NULL) {
- sdtfmt->applyPattern(style);
- }
+ // Pattern
+ styleID = findKeyword(style, DATE_STYLE_IDS);
+ date_style = (styleID >= 0) ? DATE_STYLES[styleID] : DateFormat::kDefault;
+
+ if (typeID == 1) {
+ fmt = DateFormat::createDateInstance(date_style, fLocale);
+ } else {
+ fmt = DateFormat::createTimeInstance(date_style, fLocale);
}
+
+ if (styleID < 0 && fmt != NULL) {
+ SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(fmt);
+ if (sdtfmt != NULL) {
+ sdtfmt->applyPattern(style);
+ }
+ }
}
break;
@@ -1873,7 +1873,7 @@ UBool MessageFormat::DummyFormat::operator==(const Format&) const {
return TRUE;
}
-MessageFormat::DummyFormat* MessageFormat::DummyFormat::clone() const {
+MessageFormat::DummyFormat* MessageFormat::DummyFormat::clone() const {
return new DummyFormat();
}
@@ -1976,19 +1976,19 @@ UnicodeString MessageFormat::PluralSelectorProvider::select(void *ctx, double nu
context.formatter = msgFormat.getDefaultNumberFormat(ec);
context.forReplaceNumber = TRUE;
}
- if (context.number.getDouble(ec) != number) {
- ec = U_INTERNAL_PROGRAM_ERROR;
- return UnicodeString(FALSE, OTHER_STRING, 5);
- }
+ if (context.number.getDouble(ec) != number) {
+ ec = U_INTERNAL_PROGRAM_ERROR;
+ return UnicodeString(FALSE, OTHER_STRING, 5);
+ }
context.formatter->format(context.number, context.numberString, ec);
- auto* decFmt = dynamic_cast<const DecimalFormat *>(context.formatter);
+ auto* decFmt = dynamic_cast<const DecimalFormat *>(context.formatter);
if(decFmt != NULL) {
- number::impl::DecimalQuantity dq;
- decFmt->formatToDecimalQuantity(context.number, dq, ec);
+ number::impl::DecimalQuantity dq;
+ decFmt->formatToDecimalQuantity(context.number, dq, ec);
if (U_FAILURE(ec)) {
return UnicodeString(FALSE, OTHER_STRING, 5);
}
- return rules->select(dq);
+ return rules->select(dq);
} else {
return rules->select(number);
}
diff --git a/contrib/libs/icu/i18n/msgfmt_impl.h b/contrib/libs/icu/i18n/msgfmt_impl.h
index 1cece1a094..d13112ea6a 100644
--- a/contrib/libs/icu/i18n/msgfmt_impl.h
+++ b/contrib/libs/icu/i18n/msgfmt_impl.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/name2uni.cpp b/contrib/libs/icu/i18n/name2uni.cpp
index dcf8d852e2..258de68181 100644
--- a/contrib/libs/icu/i18n/name2uni.cpp
+++ b/contrib/libs/icu/i18n/name2uni.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -100,7 +100,7 @@ NameUnicodeTransliterator::NameUnicodeTransliterator(const NameUnicodeTransliter
/**
* Transliterator API.
*/
-NameUnicodeTransliterator* NameUnicodeTransliterator::clone() const {
+NameUnicodeTransliterator* NameUnicodeTransliterator::clone() const {
return new NameUnicodeTransliterator(*this);
}
@@ -190,7 +190,7 @@ void NameUnicodeTransliterator::handleTransliterate(Replaceable& text, UTransPos
}
if (uprv_isInvariantUString(name.getBuffer(), len)) {
- cbuf[0] = 0;
+ cbuf[0] = 0;
name.extract(0, len, cbuf, maxLen, US_INV);
UErrorCode status = U_ZERO_ERROR;
diff --git a/contrib/libs/icu/i18n/name2uni.h b/contrib/libs/icu/i18n/name2uni.h
index 44ad85fb82..7e279f99db 100644
--- a/contrib/libs/icu/i18n/name2uni.h
+++ b/contrib/libs/icu/i18n/name2uni.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -49,7 +49,7 @@ public:
* Transliterator API.
* @return A copy of the object.
*/
- virtual NameUnicodeTransliterator* clone() const;
+ virtual NameUnicodeTransliterator* clone() const;
/**
* ICU "poor man's RTTI", returns a UClassID for the actual class.
diff --git a/contrib/libs/icu/i18n/nfrlist.h b/contrib/libs/icu/i18n/nfrlist.h
index 3eb1882b2f..71f4972ac0 100644
--- a/contrib/libs/icu/i18n/nfrlist.h
+++ b/contrib/libs/icu/i18n/nfrlist.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
@@ -6,7 +6,7 @@
* Corporation and others. All Rights Reserved.
******************************************************************************
* file name: nfrlist.h
-* encoding: UTF-8
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
diff --git a/contrib/libs/icu/i18n/nfrs.cpp b/contrib/libs/icu/i18n/nfrs.cpp
index e7b17b46c3..24754d201d 100644
--- a/contrib/libs/icu/i18n/nfrs.cpp
+++ b/contrib/libs/icu/i18n/nfrs.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
@@ -6,7 +6,7 @@
* Corporation and others. All Rights Reserved.
******************************************************************************
* file name: nfrs.cpp
-* encoding: UTF-8
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
@@ -23,7 +23,7 @@
#include "nfrule.h"
#include "nfrlist.h"
#include "patternprops.h"
-#include "putilimp.h"
+#include "putilimp.h"
#ifdef RBNF_DEBUG
#include "cmemory.h"
@@ -545,7 +545,7 @@ NFRuleSet::findNormalRule(int64_t number) const
// an explanation of the rollback rule). If we do, roll back
// one rule and return that one instead of the one we'd normally
// return
- if (result->shouldRollBack(number)) {
+ if (result->shouldRollBack(number)) {
if (hi == 1) { // bad rule set, no prior rule to rollback to from this base
return NULL;
}
@@ -681,7 +681,7 @@ static void dumpUS(FILE* f, const UnicodeString& us) {
#endif
UBool
-NFRuleSet::parse(const UnicodeString& text, ParsePosition& pos, double upperBound, uint32_t nonNumericalExecutedRuleMask, Formattable& result) const
+NFRuleSet::parse(const UnicodeString& text, ParsePosition& pos, double upperBound, uint32_t nonNumericalExecutedRuleMask, Formattable& result) const
{
// try matching each rule in the rule set against the text being
// parsed. Whichever one matches the most characters is the one
@@ -707,12 +707,12 @@ NFRuleSet::parse(const UnicodeString& text, ParsePosition& pos, double upperBoun
#endif
// Try each of the negative rules, fraction rules, infinity rules and NaN rules
for (int i = 0; i < NON_NUMERICAL_RULE_LENGTH; i++) {
- if (nonNumericalRules[i] && ((nonNumericalExecutedRuleMask >> i) & 1) == 0) {
- // Mark this rule as being executed so that we don't try to execute it again.
- nonNumericalExecutedRuleMask |= 1 << i;
-
+ if (nonNumericalRules[i] && ((nonNumericalExecutedRuleMask >> i) & 1) == 0) {
+ // Mark this rule as being executed so that we don't try to execute it again.
+ nonNumericalExecutedRuleMask |= 1 << i;
+
Formattable tempResult;
- UBool success = nonNumericalRules[i]->doParse(text, workingPos, 0, upperBound, nonNumericalExecutedRuleMask, tempResult);
+ UBool success = nonNumericalRules[i]->doParse(text, workingPos, 0, upperBound, nonNumericalExecutedRuleMask, tempResult);
if (success && (workingPos.getIndex() > highWaterMark.getIndex())) {
result = tempResult;
highWaterMark = workingPos;
@@ -751,7 +751,7 @@ NFRuleSet::parse(const UnicodeString& text, ParsePosition& pos, double upperBoun
continue;
}
Formattable tempResult;
- UBool success = rules[i]->doParse(text, workingPos, fIsFractionRuleSet, upperBound, nonNumericalExecutedRuleMask, tempResult);
+ UBool success = rules[i]->doParse(text, workingPos, fIsFractionRuleSet, upperBound, nonNumericalExecutedRuleMask, tempResult);
if (success && workingPos.getIndex() > highWaterMark.getIndex()) {
result = tempResult;
highWaterMark = workingPos;
@@ -833,23 +833,23 @@ int64_t util64_fromDouble(double d) {
return result;
}
-uint64_t util64_pow(uint32_t base, uint16_t exponent) {
- if (base == 0) {
+uint64_t util64_pow(uint32_t base, uint16_t exponent) {
+ if (base == 0) {
return 0;
- }
- uint64_t result = 1;
- uint64_t pow = base;
- while (true) {
- if ((exponent & 1) == 1) {
- result *= pow;
+ }
+ uint64_t result = 1;
+ uint64_t pow = base;
+ while (true) {
+ if ((exponent & 1) == 1) {
+ result *= pow;
}
- exponent >>= 1;
- if (exponent == 0) {
- break;
- }
- pow *= pow;
+ exponent >>= 1;
+ if (exponent == 0) {
+ break;
+ }
+ pow *= pow;
}
- return result;
+ return result;
}
static const uint8_t asciiDigits[] = {
diff --git a/contrib/libs/icu/i18n/nfrs.h b/contrib/libs/icu/i18n/nfrs.h
index db03c9039d..6443f096e5 100644
--- a/contrib/libs/icu/i18n/nfrs.h
+++ b/contrib/libs/icu/i18n/nfrs.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
@@ -6,7 +6,7 @@
* Corporation and others. All Rights Reserved.
******************************************************************************
* file name: nfrs.h
-* encoding: UTF-8
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
@@ -55,7 +55,7 @@ public:
void format(int64_t number, UnicodeString& toAppendTo, int32_t pos, int32_t recursionCount, UErrorCode& status) const;
void format(double number, UnicodeString& toAppendTo, int32_t pos, int32_t recursionCount, UErrorCode& status) const;
- UBool parse(const UnicodeString& text, ParsePosition& pos, double upperBound, uint32_t nonNumericalExecutedRuleMask, Formattable& result) const;
+ UBool parse(const UnicodeString& text, ParsePosition& pos, double upperBound, uint32_t nonNumericalExecutedRuleMask, Formattable& result) const;
void appendRules(UnicodeString& result) const; // toString
@@ -88,9 +88,9 @@ private:
int64_t util64_fromDouble(double d);
// raise radix to the power exponent, only non-negative exponents
-// Arithmetic is performed in unsigned space since overflow in
-// signed space is undefined behavior.
-uint64_t util64_pow(uint32_t radix, uint16_t exponent);
+// Arithmetic is performed in unsigned space since overflow in
+// signed space is undefined behavior.
+uint64_t util64_pow(uint32_t radix, uint16_t exponent);
// convert n to digit string in buffer, return length of string
uint32_t util64_tou(int64_t n, UChar* buffer, uint32_t buflen, uint32_t radix = 10, UBool raw = FALSE);
diff --git a/contrib/libs/icu/i18n/nfrule.cpp b/contrib/libs/icu/i18n/nfrule.cpp
index 3ad0291649..f6dbd61bc5 100644
--- a/contrib/libs/icu/i18n/nfrule.cpp
+++ b/contrib/libs/icu/i18n/nfrule.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
@@ -6,7 +6,7 @@
* Corporation and others. All Rights Reserved.
******************************************************************************
* file name: nfrule.cpp
-* encoding: UTF-8
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
@@ -30,7 +30,7 @@
#include "nfrlist.h"
#include "nfsubs.h"
#include "patternprops.h"
-#include "putilimp.h"
+#include "putilimp.h"
U_NAMESPACE_BEGIN
@@ -39,14 +39,14 @@ NFRule::NFRule(const RuleBasedNumberFormat* _rbnf, const UnicodeString &_ruleTex
, radix(10)
, exponent(0)
, decimalPoint(0)
- , fRuleText(_ruleText)
+ , fRuleText(_ruleText)
, sub1(NULL)
, sub2(NULL)
, formatter(_rbnf)
, rulePatternFormat(NULL)
{
- if (!fRuleText.isEmpty()) {
- parseRuleDescriptor(fRuleText, status);
+ if (!fRuleText.isEmpty()) {
+ parseRuleDescriptor(fRuleText, status);
}
}
@@ -122,7 +122,7 @@ NFRule::makeRules(UnicodeString& description,
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
- description = rule1->fRuleText;
+ description = rule1->fRuleText;
// check the description to see whether there's text enclosed
// in brackets
@@ -314,7 +314,7 @@ NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status)
if (c == gSlash) {
val = 0;
++p;
- ll_10 = 10;
+ ll_10 = 10;
while (p < descriptorLength) {
c = descriptor.charAt(p);
if (c >= gZero && c <= gNine) {
@@ -418,7 +418,7 @@ NFRule::extractSubstitutions(const NFRuleSet* ruleSet,
if (U_FAILURE(status)) {
return;
}
- fRuleText = ruleText;
+ fRuleText = ruleText;
sub1 = extractSubstitution(ruleSet, predecessor, status);
if (sub1 == NULL) {
// Small optimization. There is no need to create a redundant NullSubstitution.
@@ -427,15 +427,15 @@ NFRule::extractSubstitutions(const NFRuleSet* ruleSet,
else {
sub2 = extractSubstitution(ruleSet, predecessor, status);
}
- int32_t pluralRuleStart = fRuleText.indexOf(gDollarOpenParenthesis, -1, 0);
- int32_t pluralRuleEnd = (pluralRuleStart >= 0 ? fRuleText.indexOf(gClosedParenthesisDollar, -1, pluralRuleStart) : -1);
+ int32_t pluralRuleStart = fRuleText.indexOf(gDollarOpenParenthesis, -1, 0);
+ int32_t pluralRuleEnd = (pluralRuleStart >= 0 ? fRuleText.indexOf(gClosedParenthesisDollar, -1, pluralRuleStart) : -1);
if (pluralRuleEnd >= 0) {
- int32_t endType = fRuleText.indexOf(gComma, pluralRuleStart);
+ int32_t endType = fRuleText.indexOf(gComma, pluralRuleStart);
if (endType < 0) {
status = U_PARSE_ERROR;
return;
}
- UnicodeString type(fRuleText.tempSubString(pluralRuleStart + 2, endType - pluralRuleStart - 2));
+ UnicodeString type(fRuleText.tempSubString(pluralRuleStart + 2, endType - pluralRuleStart - 2));
UPluralType pluralType;
if (type.startsWith(UNICODE_STRING_SIMPLE("cardinal"))) {
pluralType = UPLURAL_TYPE_CARDINAL;
@@ -448,7 +448,7 @@ NFRule::extractSubstitutions(const NFRuleSet* ruleSet,
return;
}
rulePatternFormat = formatter->createPluralFormat(pluralType,
- fRuleText.tempSubString(endType + 1, pluralRuleEnd - endType - 1), status);
+ fRuleText.tempSubString(endType + 1, pluralRuleEnd - endType - 1), status);
}
}
@@ -484,16 +484,16 @@ NFRule::extractSubstitution(const NFRuleSet* ruleSet,
// special-case the ">>>" token, since searching for the > at the
// end will actually find the > in the middle
- if (fRuleText.indexOf(gGreaterGreaterGreater, 3, 0) == subStart) {
+ if (fRuleText.indexOf(gGreaterGreaterGreater, 3, 0) == subStart) {
subEnd = subStart + 2;
// otherwise the substitution token ends with the same character
// it began with
} else {
- UChar c = fRuleText.charAt(subStart);
- subEnd = fRuleText.indexOf(c, subStart + 1);
+ UChar c = fRuleText.charAt(subStart);
+ subEnd = fRuleText.indexOf(c, subStart + 1);
// special case for '<%foo<<'
- if (c == gLessThan && subEnd != -1 && subEnd < fRuleText.length() - 1 && fRuleText.charAt(subEnd+1) == c) {
+ if (c == gLessThan && subEnd != -1 && subEnd < fRuleText.length() - 1 && fRuleText.charAt(subEnd+1) == c) {
// ordinals use "=#,##0==%abbrev=" as their rule. Notice that the '==' in the middle
// occurs because of the juxtaposition of two different rules. The check for '<' is a hack
// to get around this. Having the duplicate at the front would cause problems with
@@ -513,12 +513,12 @@ NFRule::extractSubstitution(const NFRuleSet* ruleSet,
// some text bounded by substitution token characters). Use
// makeSubstitution() to create the right kind of substitution
UnicodeString subToken;
- subToken.setTo(fRuleText, subStart, subEnd + 1 - subStart);
+ subToken.setTo(fRuleText, subStart, subEnd + 1 - subStart);
result = NFSubstitution::makeSubstitution(subStart, this, predecessor, ruleSet,
this->formatter, subToken, status);
// remove the substitution from the rule text
- fRuleText.removeBetween(subStart, subEnd+1);
+ fRuleText.removeBetween(subStart, subEnd+1);
return result;
}
@@ -601,7 +601,7 @@ NFRule::indexOfAnyRulePrefix() const
{
int result = -1;
for (int i = 0; RULE_PREFIXES[i]; i++) {
- int32_t pos = fRuleText.indexOf(*RULE_PREFIXES[i]);
+ int32_t pos = fRuleText.indexOf(*RULE_PREFIXES[i]);
if (pos != -1 && (result == -1 || pos < result)) {
result = pos;
}
@@ -637,7 +637,7 @@ NFRule::operator==(const NFRule& rhs) const
return baseValue == rhs.baseValue
&& radix == rhs.radix
&& exponent == rhs.exponent
- && fRuleText == rhs.fRuleText
+ && fRuleText == rhs.fRuleText
&& util_equalSubstitutions(sub1, rhs.sub1)
&& util_equalSubstitutions(sub2, rhs.sub2);
}
@@ -690,14 +690,14 @@ NFRule::_appendRuleText(UnicodeString& result) const
// if the rule text begins with a space, write an apostrophe
// (whitespace after the rule descriptor is ignored; the
// apostrophe is used to make the whitespace significant)
- if (fRuleText.charAt(0) == gSpace && (sub1 == NULL || sub1->getPos() != 0)) {
+ if (fRuleText.charAt(0) == gSpace && (sub1 == NULL || sub1->getPos() != 0)) {
result.append(gTick);
}
// now, write the rule's rule text, inserting appropriate
// substitution tokens in the appropriate places
UnicodeString ruleTextCopy;
- ruleTextCopy.setTo(fRuleText);
+ ruleTextCopy.setTo(fRuleText);
UnicodeString temp;
if (sub2 != NULL) {
@@ -716,12 +716,12 @@ NFRule::_appendRuleText(UnicodeString& result) const
result.append(gSemicolon);
}
-int64_t NFRule::getDivisor() const
-{
- return util64_pow(radix, exponent);
-}
-
-
+int64_t NFRule::getDivisor() const
+{
+ return util64_pow(radix, exponent);
+}
+
+
//-----------------------------------------------------------------------
// formatting
//-----------------------------------------------------------------------
@@ -743,24 +743,24 @@ NFRule::doFormat(int64_t number, UnicodeString& toInsertInto, int32_t pos, int32
// into the right places in toInsertInto (notice we do the
// substitutions in reverse order so that the offsets don't get
// messed up)
- int32_t pluralRuleStart = fRuleText.length();
+ int32_t pluralRuleStart = fRuleText.length();
int32_t lengthOffset = 0;
if (!rulePatternFormat) {
- toInsertInto.insert(pos, fRuleText);
+ toInsertInto.insert(pos, fRuleText);
}
else {
- pluralRuleStart = fRuleText.indexOf(gDollarOpenParenthesis, -1, 0);
- int pluralRuleEnd = fRuleText.indexOf(gClosedParenthesisDollar, -1, pluralRuleStart);
+ pluralRuleStart = fRuleText.indexOf(gDollarOpenParenthesis, -1, 0);
+ int pluralRuleEnd = fRuleText.indexOf(gClosedParenthesisDollar, -1, pluralRuleStart);
int initialLength = toInsertInto.length();
- if (pluralRuleEnd < fRuleText.length() - 1) {
- toInsertInto.insert(pos, fRuleText.tempSubString(pluralRuleEnd + 2));
+ if (pluralRuleEnd < fRuleText.length() - 1) {
+ toInsertInto.insert(pos, fRuleText.tempSubString(pluralRuleEnd + 2));
}
toInsertInto.insert(pos,
- rulePatternFormat->format((int32_t)(number/util64_pow(radix, exponent)), status));
+ rulePatternFormat->format((int32_t)(number/util64_pow(radix, exponent)), status));
if (pluralRuleStart > 0) {
- toInsertInto.insert(pos, fRuleText.tempSubString(0, pluralRuleStart));
+ toInsertInto.insert(pos, fRuleText.tempSubString(0, pluralRuleStart));
}
- lengthOffset = fRuleText.length() - (toInsertInto.length() - initialLength);
+ lengthOffset = fRuleText.length() - (toInsertInto.length() - initialLength);
}
if (sub2 != NULL) {
@@ -789,32 +789,32 @@ NFRule::doFormat(double number, UnicodeString& toInsertInto, int32_t pos, int32_
// [again, we have two copies of this routine that do the same thing
// so that we don't sacrifice precision in a long by casting it
// to a double]
- int32_t pluralRuleStart = fRuleText.length();
+ int32_t pluralRuleStart = fRuleText.length();
int32_t lengthOffset = 0;
if (!rulePatternFormat) {
- toInsertInto.insert(pos, fRuleText);
+ toInsertInto.insert(pos, fRuleText);
}
else {
- pluralRuleStart = fRuleText.indexOf(gDollarOpenParenthesis, -1, 0);
- int pluralRuleEnd = fRuleText.indexOf(gClosedParenthesisDollar, -1, pluralRuleStart);
+ pluralRuleStart = fRuleText.indexOf(gDollarOpenParenthesis, -1, 0);
+ int pluralRuleEnd = fRuleText.indexOf(gClosedParenthesisDollar, -1, pluralRuleStart);
int initialLength = toInsertInto.length();
- if (pluralRuleEnd < fRuleText.length() - 1) {
- toInsertInto.insert(pos, fRuleText.tempSubString(pluralRuleEnd + 2));
+ if (pluralRuleEnd < fRuleText.length() - 1) {
+ toInsertInto.insert(pos, fRuleText.tempSubString(pluralRuleEnd + 2));
}
double pluralVal = number;
if (0 <= pluralVal && pluralVal < 1) {
// We're in a fractional rule, and we have to match the NumeratorSubstitution behavior.
// 2.3 can become 0.2999999999999998 for the fraction due to rounding errors.
- pluralVal = uprv_round(pluralVal * util64_pow(radix, exponent));
+ pluralVal = uprv_round(pluralVal * util64_pow(radix, exponent));
}
else {
- pluralVal = pluralVal / util64_pow(radix, exponent);
+ pluralVal = pluralVal / util64_pow(radix, exponent);
}
toInsertInto.insert(pos, rulePatternFormat->format((int32_t)(pluralVal), status));
if (pluralRuleStart > 0) {
- toInsertInto.insert(pos, fRuleText.tempSubString(0, pluralRuleStart));
+ toInsertInto.insert(pos, fRuleText.tempSubString(0, pluralRuleStart));
}
- lengthOffset = fRuleText.length() - (toInsertInto.length() - initialLength);
+ lengthOffset = fRuleText.length() - (toInsertInto.length() - initialLength);
}
if (sub2 != NULL) {
@@ -834,7 +834,7 @@ NFRule::doFormat(double number, UnicodeString& toInsertInto, int32_t pos, int32_
* this one in its list; false if it should use this rule
*/
UBool
-NFRule::shouldRollBack(int64_t number) const
+NFRule::shouldRollBack(int64_t number) const
{
// we roll back if the rule contains a modulus substitution,
// the number being formatted is an even multiple of the rule's
@@ -854,7 +854,7 @@ NFRule::shouldRollBack(int64_t number) const
// multiple of 100. This is called the "rollback rule."
if ((sub1 != NULL && sub1->isModulusSubstitution()) || (sub2 != NULL && sub2->isModulusSubstitution())) {
int64_t re = util64_pow(radix, exponent);
- return (number % re) == 0 && (baseValue % re) != 0;
+ return (number % re) == 0 && (baseValue % re) != 0;
}
return FALSE;
}
@@ -900,7 +900,7 @@ NFRule::doParse(const UnicodeString& text,
ParsePosition& parsePosition,
UBool isFractionRule,
double upperBound,
- uint32_t nonNumericalExecutedRuleMask,
+ uint32_t nonNumericalExecutedRuleMask,
Formattable& resVal) const
{
// internally we operate on a copy of the string being parsed
@@ -908,15 +908,15 @@ NFRule::doParse(const UnicodeString& text,
ParsePosition pp;
UnicodeString workText(text);
- int32_t sub1Pos = sub1 != NULL ? sub1->getPos() : fRuleText.length();
- int32_t sub2Pos = sub2 != NULL ? sub2->getPos() : fRuleText.length();
+ int32_t sub1Pos = sub1 != NULL ? sub1->getPos() : fRuleText.length();
+ int32_t sub2Pos = sub2 != NULL ? sub2->getPos() : fRuleText.length();
// check to see whether the text before the first substitution
// matches the text at the beginning of the string being
// parsed. If it does, strip that off the front of workText;
// otherwise, dump out with a mismatch
UnicodeString prefix;
- prefix.setTo(fRuleText, 0, sub1Pos);
+ prefix.setTo(fRuleText, 0, sub1Pos);
#ifdef RBNF_DEBUG
fprintf(stderr, "doParse %p ", this);
@@ -1000,10 +1000,10 @@ NFRule::doParse(const UnicodeString& text,
// the substitution, giving us a new partial parse result
pp.setIndex(0);
- temp.setTo(fRuleText, sub1Pos, sub2Pos - sub1Pos);
+ temp.setTo(fRuleText, sub1Pos, sub2Pos - sub1Pos);
double partialResult = matchToDelimiter(workText, start, tempBaseValue,
temp, pp, sub1,
- nonNumericalExecutedRuleMask,
+ nonNumericalExecutedRuleMask,
upperBound);
// if we got a successful match (or were trying to match a
@@ -1021,10 +1021,10 @@ NFRule::doParse(const UnicodeString& text,
// partial result with whatever it gets back from its
// substitution if there's a successful match, giving us
// a real result
- temp.setTo(fRuleText, sub2Pos, fRuleText.length() - sub2Pos);
+ temp.setTo(fRuleText, sub2Pos, fRuleText.length() - sub2Pos);
partialResult = matchToDelimiter(workText2, 0, partialResult,
temp, pp2, sub2,
- nonNumericalExecutedRuleMask,
+ nonNumericalExecutedRuleMask,
upperBound);
// if we got a successful match on this second
@@ -1039,18 +1039,18 @@ NFRule::doParse(const UnicodeString& text,
else {
// commented out because ParsePosition doesn't have error index in 1.1.x
// restored for ICU4C port
- int32_t i_temp = pp2.getErrorIndex() + sub1Pos + pp.getIndex();
- if (i_temp> parsePosition.getErrorIndex()) {
- parsePosition.setErrorIndex(i_temp);
+ int32_t i_temp = pp2.getErrorIndex() + sub1Pos + pp.getIndex();
+ if (i_temp> parsePosition.getErrorIndex()) {
+ parsePosition.setErrorIndex(i_temp);
}
}
}
else {
// commented out because ParsePosition doesn't have error index in 1.1.x
// restored for ICU4C port
- int32_t i_temp = sub1Pos + pp.getErrorIndex();
- if (i_temp > parsePosition.getErrorIndex()) {
- parsePosition.setErrorIndex(i_temp);
+ int32_t i_temp = sub1Pos + pp.getErrorIndex();
+ if (i_temp > parsePosition.getErrorIndex()) {
+ parsePosition.setErrorIndex(i_temp);
}
}
// keep trying to match things until the outer matchToDelimiter()
@@ -1161,7 +1161,7 @@ NFRule::matchToDelimiter(const UnicodeString& text,
const UnicodeString& delimiter,
ParsePosition& pp,
const NFSubstitution* sub,
- uint32_t nonNumericalExecutedRuleMask,
+ uint32_t nonNumericalExecutedRuleMask,
double upperBound) const
{
UErrorCode status = U_ZERO_ERROR;
@@ -1195,7 +1195,7 @@ NFRule::matchToDelimiter(const UnicodeString& text,
#else
formatter->isLenient(),
#endif
- nonNumericalExecutedRuleMask,
+ nonNumericalExecutedRuleMask,
result);
// if the substitution could match all the text up to
@@ -1249,7 +1249,7 @@ NFRule::matchToDelimiter(const UnicodeString& text,
#else
formatter->isLenient(),
#endif
- nonNumericalExecutedRuleMask,
+ nonNumericalExecutedRuleMask,
result);
if (success && (tempPP.getIndex() != 0)) {
// if there's a successful match (or it's a null
@@ -1483,11 +1483,11 @@ NFRule::findText(const UnicodeString& str,
rulePatternFormat->parseType(str, this, result, position);
int start = position.getBeginIndex();
if (start >= 0) {
- int32_t pluralRuleStart = fRuleText.indexOf(gDollarOpenParenthesis, -1, 0);
- int32_t pluralRuleSuffix = fRuleText.indexOf(gClosedParenthesisDollar, -1, pluralRuleStart) + 2;
+ int32_t pluralRuleStart = fRuleText.indexOf(gDollarOpenParenthesis, -1, 0);
+ int32_t pluralRuleSuffix = fRuleText.indexOf(gClosedParenthesisDollar, -1, pluralRuleStart) + 2;
int32_t matchLen = position.getEndIndex() - start;
- UnicodeString prefix(fRuleText.tempSubString(0, pluralRuleStart));
- UnicodeString suffix(fRuleText.tempSubString(pluralRuleSuffix));
+ UnicodeString prefix(fRuleText.tempSubString(0, pluralRuleStart));
+ UnicodeString suffix(fRuleText.tempSubString(pluralRuleSuffix));
if (str.compare(start - prefix.length(), prefix.length(), prefix, 0, prefix.length()) == 0
&& str.compare(start + matchLen, suffix.length(), suffix, 0, suffix.length()) == 0)
{
diff --git a/contrib/libs/icu/i18n/nfrule.h b/contrib/libs/icu/i18n/nfrule.h
index ed33eaa5af..721486f9d6 100644
--- a/contrib/libs/icu/i18n/nfrule.h
+++ b/contrib/libs/icu/i18n/nfrule.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -65,7 +65,7 @@ public:
UChar getDecimalPoint() const { return decimalPoint; }
- int64_t getDivisor() const;
+ int64_t getDivisor() const;
void doFormat(int64_t number, UnicodeString& toAppendTo, int32_t pos, int32_t recursionCount, UErrorCode& status) const;
void doFormat(double number, UnicodeString& toAppendTo, int32_t pos, int32_t recursionCount, UErrorCode& status) const;
@@ -74,10 +74,10 @@ public:
ParsePosition& pos,
UBool isFractional,
double upperBound,
- uint32_t nonNumericalExecutedRuleMask,
+ uint32_t nonNumericalExecutedRuleMask,
Formattable& result) const;
- UBool shouldRollBack(int64_t number) const;
+ UBool shouldRollBack(int64_t number) const;
void _appendRuleText(UnicodeString& result) const;
@@ -95,7 +95,7 @@ private:
int32_t indexOfAnyRulePrefix() const;
double matchToDelimiter(const UnicodeString& text, int32_t startPos, double baseValue,
const UnicodeString& delimiter, ParsePosition& pp, const NFSubstitution* sub,
- uint32_t nonNumericalExecutedRuleMask,
+ uint32_t nonNumericalExecutedRuleMask,
double upperBound) const;
void stripPrefix(UnicodeString& text, const UnicodeString& prefix, ParsePosition& pp) const;
@@ -109,7 +109,7 @@ private:
int32_t radix;
int16_t exponent;
UChar decimalPoint;
- UnicodeString fRuleText;
+ UnicodeString fRuleText;
NFSubstitution* sub1;
NFSubstitution* sub2;
const RuleBasedNumberFormat* formatter;
diff --git a/contrib/libs/icu/i18n/nfsubs.cpp b/contrib/libs/icu/i18n/nfsubs.cpp
index 208543d1ac..95f00fbe38 100644
--- a/contrib/libs/icu/i18n/nfsubs.cpp
+++ b/contrib/libs/icu/i18n/nfsubs.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
@@ -6,7 +6,7 @@
* Corporation and others. All Rights Reserved.
******************************************************************************
* file name: nfsubs.cpp
-* encoding: UTF-8
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
@@ -19,9 +19,9 @@
#include "utypeinfo.h" // for 'typeid' to work
#include "nfsubs.h"
-#include "fmtableimp.h"
-#include "putilimp.h"
-#include "number_decimalquantity.h"
+#include "fmtableimp.h"
+#include "putilimp.h"
+#include "number_decimalquantity.h"
#if U_HAVE_RBNF
@@ -48,8 +48,8 @@ static const UChar gGreaterGreaterThan[] =
U_NAMESPACE_BEGIN
-using number::impl::DecimalQuantity;
-
+using number::impl::DecimalQuantity;
+
class SameValueSubstitution : public NFSubstitution {
public:
SameValueSubstitution(int32_t pos,
@@ -72,15 +72,15 @@ public:
SameValueSubstitution::~SameValueSubstitution() {}
class MultiplierSubstitution : public NFSubstitution {
- int64_t divisor;
+ int64_t divisor;
public:
MultiplierSubstitution(int32_t _pos,
- const NFRule *rule,
+ const NFRule *rule,
const NFRuleSet* _ruleSet,
const UnicodeString& description,
UErrorCode& status)
- : NFSubstitution(_pos, _ruleSet, description, status), divisor(rule->getDivisor())
+ : NFSubstitution(_pos, _ruleSet, description, status), divisor(rule->getDivisor())
{
if (divisor == 0) {
status = U_PARSE_ERROR;
@@ -88,8 +88,8 @@ public:
}
virtual ~MultiplierSubstitution();
- virtual void setDivisor(int32_t radix, int16_t exponent, UErrorCode& status) {
- divisor = util64_pow(radix, exponent);
+ virtual void setDivisor(int32_t radix, int16_t exponent, UErrorCode& status) {
+ divisor = util64_pow(radix, exponent);
if(divisor == 0) {
status = U_PARSE_ERROR;
@@ -99,14 +99,14 @@ public:
virtual UBool operator==(const NFSubstitution& rhs) const;
virtual int64_t transformNumber(int64_t number) const {
- return number / divisor;
+ return number / divisor;
}
virtual double transformNumber(double number) const {
if (getRuleSet()) {
return uprv_floor(number / divisor);
} else {
- return number / divisor;
+ return number / divisor;
}
}
@@ -114,7 +114,7 @@ public:
return newRuleValue * divisor;
}
- virtual double calcUpperBound(double /*oldUpperBound*/) const { return static_cast<double>(divisor); }
+ virtual double calcUpperBound(double /*oldUpperBound*/) const { return static_cast<double>(divisor); }
virtual UChar tokenChar() const { return (UChar)0x003c; } // '<'
@@ -126,19 +126,19 @@ public:
MultiplierSubstitution::~MultiplierSubstitution() {}
class ModulusSubstitution : public NFSubstitution {
- int64_t divisor;
+ int64_t divisor;
const NFRule* ruleToUse;
public:
ModulusSubstitution(int32_t pos,
- const NFRule* rule,
+ const NFRule* rule,
const NFRule* rulePredecessor,
const NFRuleSet* ruleSet,
const UnicodeString& description,
UErrorCode& status);
virtual ~ModulusSubstitution();
- virtual void setDivisor(int32_t radix, int16_t exponent, UErrorCode& status) {
- divisor = util64_pow(radix, exponent);
+ virtual void setDivisor(int32_t radix, int16_t exponent, UErrorCode& status) {
+ divisor = util64_pow(radix, exponent);
if (divisor == 0) {
status = U_PARSE_ERROR;
@@ -150,22 +150,22 @@ public:
virtual void doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t pos, int32_t recursionCount, UErrorCode& status) const;
virtual void doSubstitution(double number, UnicodeString& toInsertInto, int32_t pos, int32_t recursionCount, UErrorCode& status) const;
- virtual int64_t transformNumber(int64_t number) const { return number % divisor; }
- virtual double transformNumber(double number) const { return uprv_fmod(number, static_cast<double>(divisor)); }
+ virtual int64_t transformNumber(int64_t number) const { return number % divisor; }
+ virtual double transformNumber(double number) const { return uprv_fmod(number, static_cast<double>(divisor)); }
virtual UBool doParse(const UnicodeString& text,
ParsePosition& parsePosition,
double baseValue,
double upperBound,
UBool lenientParse,
- uint32_t nonNumericalExecutedRuleMask,
+ uint32_t nonNumericalExecutedRuleMask,
Formattable& result) const;
virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const {
- return oldRuleValue - uprv_fmod(oldRuleValue, static_cast<double>(divisor)) + newRuleValue;
+ return oldRuleValue - uprv_fmod(oldRuleValue, static_cast<double>(divisor)) + newRuleValue;
}
- virtual double calcUpperBound(double /*oldUpperBound*/) const { return static_cast<double>(divisor); }
+ virtual double calcUpperBound(double /*oldUpperBound*/) const { return static_cast<double>(divisor); }
virtual UBool isModulusSubstitution() const { return TRUE; }
@@ -225,7 +225,7 @@ public:
double baseValue,
double upperBound,
UBool lenientParse,
- uint32_t nonNumericalExecutedRuleMask,
+ uint32_t nonNumericalExecutedRuleMask,
Formattable& result) const;
virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const { return newRuleValue + oldRuleValue; }
@@ -297,7 +297,7 @@ public:
double baseValue,
double upperBound,
UBool /*lenientParse*/,
- uint32_t nonNumericalExecutedRuleMask,
+ uint32_t nonNumericalExecutedRuleMask,
Formattable& result) const;
virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const { return newRuleValue / oldRuleValue; }
@@ -355,7 +355,7 @@ NFSubstitution::makeSubstitution(int32_t pos,
// otherwise, return a MultiplierSubstitution
else {
- return new MultiplierSubstitution(pos, rule, ruleSet,
+ return new MultiplierSubstitution(pos, rule, ruleSet,
description, status);
}
@@ -385,7 +385,7 @@ NFSubstitution::makeSubstitution(int32_t pos,
// otherwise, return a ModulusSubstitution
else {
- return new ModulusSubstitution(pos, rule, predecessor,
+ return new ModulusSubstitution(pos, rule, predecessor,
ruleSet, description, status);
}
@@ -493,7 +493,7 @@ NFSubstitution::~NFSubstitution()
* @param exponent The exponent of the divisor
*/
void
-NFSubstitution::setDivisor(int32_t /*radix*/, int16_t /*exponent*/, UErrorCode& /*status*/) {
+NFSubstitution::setDivisor(int32_t /*radix*/, int16_t /*exponent*/, UErrorCode& /*status*/) {
// a no-op for all substitutions except multiplier and modulus substitutions
}
@@ -574,38 +574,38 @@ void
NFSubstitution::doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t _pos, int32_t recursionCount, UErrorCode& status) const
{
if (ruleSet != NULL) {
- // Perform a transformation on the number that is dependent
+ // Perform a transformation on the number that is dependent
// on the type of substitution this is, then just call its
// rule set's format() method to format the result
ruleSet->format(transformNumber(number), toInsertInto, _pos + this->pos, recursionCount, status);
} else if (numberFormat != NULL) {
- if (number <= MAX_INT64_IN_DOUBLE) {
- // or perform the transformation on the number (preserving
- // the result's fractional part if the formatter it set
- // to show it), then use that formatter's format() method
- // to format the result
- double numberToFormat = transformNumber((double)number);
- if (numberFormat->getMaximumFractionDigits() == 0) {
- numberToFormat = uprv_floor(numberToFormat);
- }
-
- UnicodeString temp;
- numberFormat->format(numberToFormat, temp, status);
- toInsertInto.insert(_pos + this->pos, temp);
- }
- else {
- // We have gone beyond double precision. Something has to give.
- // We're favoring accuracy of the large number over potential rules
- // that round like a CompactDecimalFormat, which is not a common use case.
- //
- // Perform a transformation on the number that is dependent
- // on the type of substitution this is, then just call its
- // rule set's format() method to format the result
- int64_t numberToFormat = transformNumber(number);
- UnicodeString temp;
- numberFormat->format(numberToFormat, temp, status);
- toInsertInto.insert(_pos + this->pos, temp);
- }
+ if (number <= MAX_INT64_IN_DOUBLE) {
+ // or perform the transformation on the number (preserving
+ // the result's fractional part if the formatter it set
+ // to show it), then use that formatter's format() method
+ // to format the result
+ double numberToFormat = transformNumber((double)number);
+ if (numberFormat->getMaximumFractionDigits() == 0) {
+ numberToFormat = uprv_floor(numberToFormat);
+ }
+
+ UnicodeString temp;
+ numberFormat->format(numberToFormat, temp, status);
+ toInsertInto.insert(_pos + this->pos, temp);
+ }
+ else {
+ // We have gone beyond double precision. Something has to give.
+ // We're favoring accuracy of the large number over potential rules
+ // that round like a CompactDecimalFormat, which is not a common use case.
+ //
+ // Perform a transformation on the number that is dependent
+ // on the type of substitution this is, then just call its
+ // rule set's format() method to format the result
+ int64_t numberToFormat = transformNumber(number);
+ UnicodeString temp;
+ numberFormat->format(numberToFormat, temp, status);
+ toInsertInto.insert(_pos + this->pos, temp);
+ }
}
}
@@ -695,7 +695,7 @@ NFSubstitution::doParse(const UnicodeString& text,
double baseValue,
double upperBound,
UBool lenientParse,
- uint32_t nonNumericalExecutedRuleMask,
+ uint32_t nonNumericalExecutedRuleMask,
Formattable& result) const
{
#ifdef RBNF_DEBUG
@@ -716,7 +716,7 @@ NFSubstitution::doParse(const UnicodeString& text,
// on), then also try parsing the text using a default-
// constructed NumberFormat
if (ruleSet != NULL) {
- ruleSet->parse(text, parsePosition, upperBound, nonNumericalExecutedRuleMask, result);
+ ruleSet->parse(text, parsePosition, upperBound, nonNumericalExecutedRuleMask, result);
if (lenientParse && !ruleSet->isFractionRuleSet() && parsePosition.getIndex() == 0) {
UErrorCode status = U_ZERO_ERROR;
NumberFormat* fmt = NumberFormat::createInstance(status);
@@ -827,20 +827,20 @@ UBool MultiplierSubstitution::operator==(const NFSubstitution& rhs) const
* regular rule.
*/
ModulusSubstitution::ModulusSubstitution(int32_t _pos,
- const NFRule* rule,
+ const NFRule* rule,
const NFRule* predecessor,
const NFRuleSet* _ruleSet,
const UnicodeString& description,
UErrorCode& status)
: NFSubstitution(_pos, _ruleSet, description, status)
- , divisor(rule->getDivisor())
+ , divisor(rule->getDivisor())
, ruleToUse(NULL)
{
// the owning rule's divisor controls the behavior of this
// substitution: rather than keeping a backpointer to the rule,
// we keep a copy of the divisor
- if (divisor == 0) {
+ if (divisor == 0) {
status = U_PARSE_ERROR;
}
@@ -938,19 +938,19 @@ ModulusSubstitution::doParse(const UnicodeString& text,
double baseValue,
double upperBound,
UBool lenientParse,
- uint32_t nonNumericalExecutedRuleMask,
+ uint32_t nonNumericalExecutedRuleMask,
Formattable& result) const
{
// if this isn't a >>> substitution, we can just use the
// inherited parse() routine to do the parsing
if (ruleToUse == NULL) {
- return NFSubstitution::doParse(text, parsePosition, baseValue, upperBound, lenientParse, nonNumericalExecutedRuleMask, result);
+ return NFSubstitution::doParse(text, parsePosition, baseValue, upperBound, lenientParse, nonNumericalExecutedRuleMask, result);
// but if it IS a >>> substitution, we have to do it here: we
// use the specific rule's doParse() method, and then we have to
// do some of the other work of NFRuleSet.parse()
} else {
- ruleToUse->doParse(text, parsePosition, FALSE, upperBound, nonNumericalExecutedRuleMask, result);
+ ruleToUse->doParse(text, parsePosition, FALSE, upperBound, nonNumericalExecutedRuleMask, result);
if (parsePosition.getIndex() != 0) {
UErrorCode status = U_ZERO_ERROR;
@@ -1072,12 +1072,12 @@ FractionalPartSubstitution::doSubstitution(double number, UnicodeString& toInser
// numberToFormat /= 10;
// }
- DecimalQuantity dl;
- dl.setToDouble(number);
- dl.roundToMagnitude(-20, UNUM_ROUND_HALFEVEN, status); // round to 20 fraction digits.
+ 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.getLowerDisplayMagnitude(); didx<0; 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.
@@ -1086,7 +1086,7 @@ FractionalPartSubstitution::doSubstitution(double number, UnicodeString& toInser
} else {
pad = TRUE;
}
- int64_t digit = dl.getDigit(didx);
+ int64_t digit = dl.getDigit(didx);
getRuleSet()->format(digit, toInsertInto, _pos + getPos(), recursionCount, status);
}
@@ -1125,13 +1125,13 @@ FractionalPartSubstitution::doParse(const UnicodeString& text,
double baseValue,
double /*upperBound*/,
UBool lenientParse,
- uint32_t nonNumericalExecutedRuleMask,
+ uint32_t nonNumericalExecutedRuleMask,
Formattable& resVal) const
{
// if we're not in byDigits mode, we can just use the inherited
// doParse()
if (!byDigits) {
- return NFSubstitution::doParse(text, parsePosition, baseValue, 0, lenientParse, nonNumericalExecutedRuleMask, resVal);
+ return NFSubstitution::doParse(text, parsePosition, baseValue, 0, lenientParse, nonNumericalExecutedRuleMask, resVal);
// if we ARE in byDigits mode, parse the text one digit at a time
// using this substitution's owning rule set (we do this by setting
@@ -1144,13 +1144,13 @@ FractionalPartSubstitution::doParse(const UnicodeString& text,
int32_t digit;
// double p10 = 0.1;
- DecimalQuantity dl;
- int32_t totalDigits = 0;
+ DecimalQuantity dl;
+ int32_t totalDigits = 0;
NumberFormat* fmt = NULL;
while (workText.length() > 0 && workPos.getIndex() != 0) {
workPos.setIndex(0);
Formattable temp;
- getRuleSet()->parse(workText, workPos, 10, nonNumericalExecutedRuleMask, temp);
+ getRuleSet()->parse(workText, workPos, 10, nonNumericalExecutedRuleMask, temp);
UErrorCode status = U_ZERO_ERROR;
digit = temp.getLong(status);
// digit = temp.getType() == Formattable::kLong ?
@@ -1173,8 +1173,8 @@ FractionalPartSubstitution::doParse(const UnicodeString& text,
}
if (workPos.getIndex() != 0) {
- dl.appendDigit(static_cast<int8_t>(digit), 0, true);
- totalDigits++;
+ dl.appendDigit(static_cast<int8_t>(digit), 0, true);
+ totalDigits++;
// result += digit * p10;
// p10 /= 10;
parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex());
@@ -1187,8 +1187,8 @@ FractionalPartSubstitution::doParse(const UnicodeString& text,
}
delete fmt;
- dl.adjustMagnitude(-totalDigits);
- result = dl.toDouble();
+ dl.adjustMagnitude(-totalDigits);
+ result = dl.toDouble();
result = composeRuleValue(result, baseValue);
resVal.setDouble(result);
return TRUE;
@@ -1260,7 +1260,7 @@ NumeratorSubstitution::doParse(const UnicodeString& text,
double baseValue,
double upperBound,
UBool /*lenientParse*/,
- uint32_t nonNumericalExecutedRuleMask,
+ uint32_t nonNumericalExecutedRuleMask,
Formattable& result) const
{
// we don't have to do anything special to do the parsing here,
@@ -1279,7 +1279,7 @@ NumeratorSubstitution::doParse(const UnicodeString& text,
while (workText.length() > 0 && workPos.getIndex() != 0) {
workPos.setIndex(0);
- getRuleSet()->parse(workText, workPos, 1, nonNumericalExecutedRuleMask, temp); // parse zero or nothing at all
+ getRuleSet()->parse(workText, workPos, 1, nonNumericalExecutedRuleMask, temp); // parse zero or nothing at all
if (workPos.getIndex() == 0) {
// we failed, either there were no more zeros, or the number was formatted with digits
// either way, we're done
@@ -1301,7 +1301,7 @@ NumeratorSubstitution::doParse(const UnicodeString& text,
}
// we've parsed off the zeros, now let's parse the rest from our current position
- NFSubstitution::doParse(workText, parsePosition, withZeros ? 1 : baseValue, upperBound, FALSE, nonNumericalExecutedRuleMask, result);
+ NFSubstitution::doParse(workText, parsePosition, withZeros ? 1 : baseValue, upperBound, FALSE, nonNumericalExecutedRuleMask, result);
if (withZeros) {
// any base value will do in this case. is there a way to
diff --git a/contrib/libs/icu/i18n/nfsubs.h b/contrib/libs/icu/i18n/nfsubs.h
index 948627c0cc..81b8b323b4 100644
--- a/contrib/libs/icu/i18n/nfsubs.h
+++ b/contrib/libs/icu/i18n/nfsubs.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
@@ -6,7 +6,7 @@
* Corporation and others. All Rights Reserved.
******************************************************************************
* file name: nfsubs.h
-* encoding: UTF-8
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
@@ -91,7 +91,7 @@ public:
* @param radix The radix of the divisor
* @param exponent The exponent of the divisor
*/
- virtual void setDivisor(int32_t radix, int16_t exponent, UErrorCode& status);
+ virtual void setDivisor(int32_t radix, int16_t exponent, UErrorCode& status);
/**
* Replaces result with the string describing the substitution.
@@ -191,7 +191,7 @@ public:
double baseValue,
double upperBound,
UBool lenientParse,
- uint32_t nonNumericalExecutedRuleMask,
+ uint32_t nonNumericalExecutedRuleMask,
Formattable& result) const;
/**
diff --git a/contrib/libs/icu/i18n/nortrans.cpp b/contrib/libs/icu/i18n/nortrans.cpp
index 6a8d2c7419..6c63215db8 100644
--- a/contrib/libs/icu/i18n/nortrans.cpp
+++ b/contrib/libs/icu/i18n/nortrans.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -92,7 +92,7 @@ NormalizationTransliterator::NormalizationTransliterator(const NormalizationTran
/**
* Transliterator API.
*/
-NormalizationTransliterator* NormalizationTransliterator::clone() const {
+NormalizationTransliterator* NormalizationTransliterator::clone() const {
return new NormalizationTransliterator(*this);
}
diff --git a/contrib/libs/icu/i18n/nortrans.h b/contrib/libs/icu/i18n/nortrans.h
index 198ed29c95..7d831aa665 100644
--- a/contrib/libs/icu/i18n/nortrans.h
+++ b/contrib/libs/icu/i18n/nortrans.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -44,7 +44,7 @@ class NormalizationTransliterator : public Transliterator {
* Transliterator API.
* @return A copy of the object.
*/
- virtual NormalizationTransliterator* clone() const;
+ virtual NormalizationTransliterator* clone() const;
/**
* ICU "poor man's RTTI", returns a UClassID for the actual class.
diff --git a/contrib/libs/icu/i18n/nounit.cpp b/contrib/libs/icu/i18n/nounit.cpp
index 1d4aa05506..49e574bf5d 100644
--- a/contrib/libs/icu/i18n/nounit.cpp
+++ b/contrib/libs/icu/i18n/nounit.cpp
@@ -1,42 +1,42 @@
-// © 2017 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html
-
-#include "unicode/nounit.h"
-#include "uassert.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-U_NAMESPACE_BEGIN
-
-UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NoUnit)
-
-NoUnit U_EXPORT2 NoUnit::base() {
- return NoUnit("");
-}
-
-NoUnit U_EXPORT2 NoUnit::percent() {
- return NoUnit("percent");
-}
-
-NoUnit U_EXPORT2 NoUnit::permille() {
- return NoUnit("permille");
-}
-
-NoUnit::NoUnit(const char* subtype) {
- initNoUnit(subtype);
-}
-
-NoUnit::NoUnit(const NoUnit& other) : MeasureUnit(other) {
-}
-
-NoUnit* NoUnit::clone() const {
- return new NoUnit(*this);
-}
-
-NoUnit::~NoUnit() {
-}
-
-
-U_NAMESPACE_END
-
-#endif
+// © 2017 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#include "unicode/nounit.h"
+#include "uassert.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NoUnit)
+
+NoUnit U_EXPORT2 NoUnit::base() {
+ return NoUnit("");
+}
+
+NoUnit U_EXPORT2 NoUnit::percent() {
+ return NoUnit("percent");
+}
+
+NoUnit U_EXPORT2 NoUnit::permille() {
+ return NoUnit("permille");
+}
+
+NoUnit::NoUnit(const char* subtype) {
+ initNoUnit(subtype);
+}
+
+NoUnit::NoUnit(const NoUnit& other) : MeasureUnit(other) {
+}
+
+NoUnit* NoUnit::clone() const {
+ return new NoUnit(*this);
+}
+
+NoUnit::~NoUnit() {
+}
+
+
+U_NAMESPACE_END
+
+#endif
diff --git a/contrib/libs/icu/i18n/nultrans.cpp b/contrib/libs/icu/i18n/nultrans.cpp
index 439cc55d38..70403ce857 100644
--- a/contrib/libs/icu/i18n/nultrans.cpp
+++ b/contrib/libs/icu/i18n/nultrans.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -24,7 +24,7 @@ NullTransliterator::NullTransliterator() : Transliterator(UNICODE_STRING_SIMPLE(
NullTransliterator::~NullTransliterator() {}
-NullTransliterator* NullTransliterator::clone() const {
+NullTransliterator* NullTransliterator::clone() const {
return new NullTransliterator();
}
diff --git a/contrib/libs/icu/i18n/nultrans.h b/contrib/libs/icu/i18n/nultrans.h
index 36c92fa7b1..1cff5de175 100644
--- a/contrib/libs/icu/i18n/nultrans.h
+++ b/contrib/libs/icu/i18n/nultrans.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -45,7 +45,7 @@ public:
* Transliterator API.
* @internal Use transliterator factory methods instead since this class will be removed in that release.
*/
- virtual NullTransliterator* clone() const;
+ virtual NullTransliterator* clone() const;
/**
* Implements {@link Transliterator#handleTransliterate}.
diff --git a/contrib/libs/icu/i18n/number_affixutils.cpp b/contrib/libs/icu/i18n/number_affixutils.cpp
index a74ec2d634..2a437ada22 100644
--- a/contrib/libs/icu/i18n/number_affixutils.cpp
+++ b/contrib/libs/icu/i18n/number_affixutils.cpp
@@ -1,440 +1,440 @@
-// © 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
-
-#include "number_affixutils.h"
-#include "unicode/utf16.h"
-#include "unicode/uniset.h"
-
-using namespace icu;
-using namespace icu::number;
-using namespace icu::number::impl;
-
-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.char32At(offset);
-
- switch (state) {
- case STATE_BASE:
- if (cp == u'\'') {
- // First quote
- state = STATE_FIRST_QUOTE;
- } else {
- // Unquoted symbol
- length++;
- }
- break;
- case STATE_FIRST_QUOTE:
- if (cp == u'\'') {
- // Repeated quote
- length++;
- state = STATE_BASE;
- } else {
- // Quoted code point
- length++;
- state = STATE_INSIDE_QUOTE;
- }
- break;
- case STATE_INSIDE_QUOTE:
- if (cp == u'\'') {
- // End of quoted sequence
- state = STATE_AFTER_QUOTE;
- } else {
- // Quoted code point
- length++;
- }
- break;
- case STATE_AFTER_QUOTE:
- if (cp == u'\'') {
- // Double quote inside of quoted sequence
- length++;
- state = STATE_INSIDE_QUOTE;
- } else {
- // Unquoted symbol
- length++;
- }
- break;
- default:
- UPRV_UNREACHABLE;
- }
-
- offset += U16_LENGTH(cp);
- }
-
- switch (state) {
- case STATE_FIRST_QUOTE:
- case STATE_INSIDE_QUOTE:
- status = U_ILLEGAL_ARGUMENT_ERROR;
- break;
- default:
- break;
- }
-
- return length;
-}
-
-UnicodeString AffixUtils::escape(const UnicodeString &input) {
- AffixPatternState state = STATE_BASE;
- int32_t offset = 0;
- UnicodeString output;
- for (; offset < input.length();) {
- UChar32 cp = input.char32At(offset);
-
- switch (cp) {
- case u'\'':
- output.append(u"''", -1);
- break;
-
- case u'-':
- case u'+':
- case u'%':
- case u'‰':
- case u'¤':
- if (state == STATE_BASE) {
- output.append(u'\'');
- output.append(cp);
- state = STATE_INSIDE_QUOTE;
- } else {
- output.append(cp);
- }
- break;
-
- default:
- if (state == STATE_INSIDE_QUOTE) {
- output.append(u'\'');
- output.append(cp);
- state = STATE_BASE;
- } else {
- output.append(cp);
- }
- break;
- }
- offset += U16_LENGTH(cp);
- }
-
- if (state == STATE_INSIDE_QUOTE) {
- output.append(u'\'');
- }
-
- return output;
-}
-
-Field AffixUtils::getFieldForType(AffixPatternType type) {
- switch (type) {
- case TYPE_MINUS_SIGN:
- return {UFIELD_CATEGORY_NUMBER, UNUM_SIGN_FIELD};
- case TYPE_PLUS_SIGN:
- return {UFIELD_CATEGORY_NUMBER, UNUM_SIGN_FIELD};
- case TYPE_PERCENT:
- return {UFIELD_CATEGORY_NUMBER, UNUM_PERCENT_FIELD};
- case TYPE_PERMILLE:
- return {UFIELD_CATEGORY_NUMBER, UNUM_PERMILL_FIELD};
- case TYPE_CURRENCY_SINGLE:
- return {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD};
- case TYPE_CURRENCY_DOUBLE:
- return {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD};
- case TYPE_CURRENCY_TRIPLE:
- return {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD};
- case TYPE_CURRENCY_QUAD:
- return {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD};
- case TYPE_CURRENCY_QUINT:
- return {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD};
- case TYPE_CURRENCY_OVERFLOW:
- return {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD};
- default:
- UPRV_UNREACHABLE;
- }
-}
-
-int32_t
-AffixUtils::unescape(const UnicodeString &affixPattern, FormattedStringBuilder &output, int32_t position,
- const SymbolProvider &provider, Field field, UErrorCode &status) {
- int32_t length = 0;
- AffixTag tag;
- while (hasNext(tag, affixPattern)) {
- tag = nextToken(tag, affixPattern, status);
- if (U_FAILURE(status)) { return length; }
- if (tag.type == TYPE_CURRENCY_OVERFLOW) {
- // Don't go to the provider for this special case
- length += output.insertCodePoint(
- position + length,
- 0xFFFD,
- {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD},
- status);
- } else if (tag.type < 0) {
- length += output.insert(
- position + length, provider.getSymbol(tag.type), getFieldForType(tag.type), status);
- } else {
- length += output.insertCodePoint(position + length, tag.codePoint, field, status);
- }
- }
- return length;
-}
-
-int32_t AffixUtils::unescapedCodePointCount(const UnicodeString &affixPattern,
- const SymbolProvider &provider, UErrorCode &status) {
- int32_t length = 0;
- AffixTag tag;
- while (hasNext(tag, affixPattern)) {
- tag = nextToken(tag, affixPattern, status);
- if (U_FAILURE(status)) { return length; }
- if (tag.type == TYPE_CURRENCY_OVERFLOW) {
- length += 1;
- } else if (tag.type < 0) {
- length += provider.getSymbol(tag.type).length();
- } else {
- length += U16_LENGTH(tag.codePoint);
- }
- }
- return length;
-}
-
-bool
-AffixUtils::containsType(const UnicodeString &affixPattern, AffixPatternType type, UErrorCode &status) {
- if (affixPattern.length() == 0) {
- return false;
- }
- AffixTag tag;
- while (hasNext(tag, affixPattern)) {
- tag = nextToken(tag, affixPattern, status);
- if (U_FAILURE(status)) { return false; }
- if (tag.type == type) {
- return true;
- }
- }
- return false;
-}
-
-bool AffixUtils::hasCurrencySymbols(const UnicodeString &affixPattern, UErrorCode &status) {
- if (affixPattern.length() == 0) {
- return false;
- }
- AffixTag tag;
- while (hasNext(tag, affixPattern)) {
- tag = nextToken(tag, affixPattern, status);
- if (U_FAILURE(status)) { return false; }
- if (tag.type < 0 && getFieldForType(tag.type) == Field(UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD)) {
- return true;
- }
- }
- return false;
-}
-
-UnicodeString AffixUtils::replaceType(const UnicodeString &affixPattern, AffixPatternType type,
- char16_t replacementChar, UErrorCode &status) {
- UnicodeString output(affixPattern); // copy
- if (affixPattern.length() == 0) {
- return output;
- }
- AffixTag tag;
- while (hasNext(tag, affixPattern)) {
- tag = nextToken(tag, affixPattern, status);
- if (U_FAILURE(status)) { return output; }
- if (tag.type == type) {
- output.replace(tag.offset - 1, 1, replacementChar);
- }
- }
- return output;
-}
-
-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.char32At(offset);
- int32_t count = U16_LENGTH(cp);
-
- switch (state) {
- case STATE_BASE:
- switch (cp) {
- case u'\'':
- state = STATE_FIRST_QUOTE;
- offset += count;
- // continue to the next code point
- break;
- case u'-':
- return makeTag(offset + count, TYPE_MINUS_SIGN, STATE_BASE, 0);
- case u'+':
- return makeTag(offset + count, TYPE_PLUS_SIGN, STATE_BASE, 0);
- case u'%':
- return makeTag(offset + count, TYPE_PERCENT, STATE_BASE, 0);
- case u'‰':
- return makeTag(offset + count, TYPE_PERMILLE, STATE_BASE, 0);
- case u'¤':
- state = STATE_FIRST_CURR;
- offset += count;
- // continue to the next code point
- break;
- default:
- return makeTag(offset + count, TYPE_CODEPOINT, STATE_BASE, cp);
- }
- break;
- case STATE_FIRST_QUOTE:
- if (cp == u'\'') {
- return makeTag(offset + count, TYPE_CODEPOINT, STATE_BASE, cp);
- } else {
- return makeTag(offset + count, TYPE_CODEPOINT, STATE_INSIDE_QUOTE, cp);
- }
- case STATE_INSIDE_QUOTE:
- if (cp == u'\'') {
- state = STATE_AFTER_QUOTE;
- offset += count;
- // continue to the next code point
- break;
- } else {
- return makeTag(offset + count, TYPE_CODEPOINT, STATE_INSIDE_QUOTE, cp);
- }
- case STATE_AFTER_QUOTE:
- if (cp == u'\'') {
- return makeTag(offset + count, TYPE_CODEPOINT, STATE_INSIDE_QUOTE, cp);
- } else {
- state = STATE_BASE;
- // re-evaluate this code point
- break;
- }
- case STATE_FIRST_CURR:
- if (cp == u'¤') {
- state = STATE_SECOND_CURR;
- offset += count;
- // continue to the next code point
- break;
- } else {
- return makeTag(offset, TYPE_CURRENCY_SINGLE, STATE_BASE, 0);
- }
- case STATE_SECOND_CURR:
- if (cp == u'¤') {
- state = STATE_THIRD_CURR;
- offset += count;
- // continue to the next code point
- break;
- } else {
- return makeTag(offset, TYPE_CURRENCY_DOUBLE, STATE_BASE, 0);
- }
- case STATE_THIRD_CURR:
- if (cp == u'¤') {
- state = STATE_FOURTH_CURR;
- offset += count;
- // continue to the next code point
- break;
- } else {
- return makeTag(offset, TYPE_CURRENCY_TRIPLE, STATE_BASE, 0);
- }
- case STATE_FOURTH_CURR:
- if (cp == u'¤') {
- state = STATE_FIFTH_CURR;
- offset += count;
- // continue to the next code point
- break;
- } else {
- return makeTag(offset, TYPE_CURRENCY_QUAD, STATE_BASE, 0);
- }
- case STATE_FIFTH_CURR:
- if (cp == u'¤') {
- state = STATE_OVERFLOW_CURR;
- offset += count;
- // continue to the next code point
- break;
- } else {
- return makeTag(offset, TYPE_CURRENCY_QUINT, STATE_BASE, 0);
- }
- case STATE_OVERFLOW_CURR:
- if (cp == u'¤') {
- offset += count;
- // continue to the next code point and loop back to this state
- break;
- } else {
- return makeTag(offset, TYPE_CURRENCY_OVERFLOW, STATE_BASE, 0);
- }
- default:
- UPRV_UNREACHABLE;
- }
- }
- // End of string
- switch (state) {
- case STATE_BASE:
- // No more tokens in string.
- return {-1};
- case STATE_FIRST_QUOTE:
- case STATE_INSIDE_QUOTE:
- // For consistent behavior with the JDK and ICU 58, set an error here.
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return {-1};
- case STATE_AFTER_QUOTE:
- // No more tokens in string.
- return {-1};
- case STATE_FIRST_CURR:
- return makeTag(offset, TYPE_CURRENCY_SINGLE, STATE_BASE, 0);
- case STATE_SECOND_CURR:
- return makeTag(offset, TYPE_CURRENCY_DOUBLE, STATE_BASE, 0);
- case STATE_THIRD_CURR:
- return makeTag(offset, TYPE_CURRENCY_TRIPLE, STATE_BASE, 0);
- case STATE_FOURTH_CURR:
- return makeTag(offset, TYPE_CURRENCY_QUAD, STATE_BASE, 0);
- case STATE_FIFTH_CURR:
- return makeTag(offset, TYPE_CURRENCY_QUINT, STATE_BASE, 0);
- case STATE_OVERFLOW_CURR:
- return makeTag(offset, TYPE_CURRENCY_OVERFLOW, STATE_BASE, 0);
- default:
- UPRV_UNREACHABLE;
- }
-}
-
-bool AffixUtils::hasNext(const AffixTag &tag, const UnicodeString &string) {
- // First check for the {-1} and default initializer syntax.
- if (tag.offset < 0) {
- return false;
- } else if (tag.offset == 0) {
- return string.length() > 0;
- }
- // The rest of the fields are safe to use now.
- // Special case: the last character in string is an end quote.
- if (tag.state == STATE_INSIDE_QUOTE && tag.offset == string.length() - 1 &&
- string.charAt(tag.offset) == u'\'') {
- return false;
- } else if (tag.state != STATE_BASE) {
- return true;
- } else {
- return tag.offset < string.length();
- }
-}
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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
+
+#include "number_affixutils.h"
+#include "unicode/utf16.h"
+#include "unicode/uniset.h"
+
+using namespace icu;
+using namespace icu::number;
+using namespace icu::number::impl;
+
+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.char32At(offset);
+
+ switch (state) {
+ case STATE_BASE:
+ if (cp == u'\'') {
+ // First quote
+ state = STATE_FIRST_QUOTE;
+ } else {
+ // Unquoted symbol
+ length++;
+ }
+ break;
+ case STATE_FIRST_QUOTE:
+ if (cp == u'\'') {
+ // Repeated quote
+ length++;
+ state = STATE_BASE;
+ } else {
+ // Quoted code point
+ length++;
+ state = STATE_INSIDE_QUOTE;
+ }
+ break;
+ case STATE_INSIDE_QUOTE:
+ if (cp == u'\'') {
+ // End of quoted sequence
+ state = STATE_AFTER_QUOTE;
+ } else {
+ // Quoted code point
+ length++;
+ }
+ break;
+ case STATE_AFTER_QUOTE:
+ if (cp == u'\'') {
+ // Double quote inside of quoted sequence
+ length++;
+ state = STATE_INSIDE_QUOTE;
+ } else {
+ // Unquoted symbol
+ length++;
+ }
+ break;
+ default:
+ UPRV_UNREACHABLE;
+ }
+
+ offset += U16_LENGTH(cp);
+ }
+
+ switch (state) {
+ case STATE_FIRST_QUOTE:
+ case STATE_INSIDE_QUOTE:
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ break;
+ default:
+ break;
+ }
+
+ return length;
+}
+
+UnicodeString AffixUtils::escape(const UnicodeString &input) {
+ AffixPatternState state = STATE_BASE;
+ int32_t offset = 0;
+ UnicodeString output;
+ for (; offset < input.length();) {
+ UChar32 cp = input.char32At(offset);
+
+ switch (cp) {
+ case u'\'':
+ output.append(u"''", -1);
+ break;
+
+ case u'-':
+ case u'+':
+ case u'%':
+ case u'‰':
+ case u'¤':
+ if (state == STATE_BASE) {
+ output.append(u'\'');
+ output.append(cp);
+ state = STATE_INSIDE_QUOTE;
+ } else {
+ output.append(cp);
+ }
+ break;
+
+ default:
+ if (state == STATE_INSIDE_QUOTE) {
+ output.append(u'\'');
+ output.append(cp);
+ state = STATE_BASE;
+ } else {
+ output.append(cp);
+ }
+ break;
+ }
+ offset += U16_LENGTH(cp);
+ }
+
+ if (state == STATE_INSIDE_QUOTE) {
+ output.append(u'\'');
+ }
+
+ return output;
+}
+
+Field AffixUtils::getFieldForType(AffixPatternType type) {
+ switch (type) {
+ case TYPE_MINUS_SIGN:
+ return {UFIELD_CATEGORY_NUMBER, UNUM_SIGN_FIELD};
+ case TYPE_PLUS_SIGN:
+ return {UFIELD_CATEGORY_NUMBER, UNUM_SIGN_FIELD};
+ case TYPE_PERCENT:
+ return {UFIELD_CATEGORY_NUMBER, UNUM_PERCENT_FIELD};
+ case TYPE_PERMILLE:
+ return {UFIELD_CATEGORY_NUMBER, UNUM_PERMILL_FIELD};
+ case TYPE_CURRENCY_SINGLE:
+ return {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD};
+ case TYPE_CURRENCY_DOUBLE:
+ return {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD};
+ case TYPE_CURRENCY_TRIPLE:
+ return {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD};
+ case TYPE_CURRENCY_QUAD:
+ return {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD};
+ case TYPE_CURRENCY_QUINT:
+ return {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD};
+ case TYPE_CURRENCY_OVERFLOW:
+ return {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD};
+ default:
+ UPRV_UNREACHABLE;
+ }
+}
+
+int32_t
+AffixUtils::unescape(const UnicodeString &affixPattern, FormattedStringBuilder &output, int32_t position,
+ const SymbolProvider &provider, Field field, UErrorCode &status) {
+ int32_t length = 0;
+ AffixTag tag;
+ while (hasNext(tag, affixPattern)) {
+ tag = nextToken(tag, affixPattern, status);
+ if (U_FAILURE(status)) { return length; }
+ if (tag.type == TYPE_CURRENCY_OVERFLOW) {
+ // Don't go to the provider for this special case
+ length += output.insertCodePoint(
+ position + length,
+ 0xFFFD,
+ {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD},
+ status);
+ } else if (tag.type < 0) {
+ length += output.insert(
+ position + length, provider.getSymbol(tag.type), getFieldForType(tag.type), status);
+ } else {
+ length += output.insertCodePoint(position + length, tag.codePoint, field, status);
+ }
+ }
+ return length;
+}
+
+int32_t AffixUtils::unescapedCodePointCount(const UnicodeString &affixPattern,
+ const SymbolProvider &provider, UErrorCode &status) {
+ int32_t length = 0;
+ AffixTag tag;
+ while (hasNext(tag, affixPattern)) {
+ tag = nextToken(tag, affixPattern, status);
+ if (U_FAILURE(status)) { return length; }
+ if (tag.type == TYPE_CURRENCY_OVERFLOW) {
+ length += 1;
+ } else if (tag.type < 0) {
+ length += provider.getSymbol(tag.type).length();
+ } else {
+ length += U16_LENGTH(tag.codePoint);
+ }
+ }
+ return length;
+}
+
+bool
+AffixUtils::containsType(const UnicodeString &affixPattern, AffixPatternType type, UErrorCode &status) {
+ if (affixPattern.length() == 0) {
+ return false;
+ }
+ AffixTag tag;
+ while (hasNext(tag, affixPattern)) {
+ tag = nextToken(tag, affixPattern, status);
+ if (U_FAILURE(status)) { return false; }
+ if (tag.type == type) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AffixUtils::hasCurrencySymbols(const UnicodeString &affixPattern, UErrorCode &status) {
+ if (affixPattern.length() == 0) {
+ return false;
+ }
+ AffixTag tag;
+ while (hasNext(tag, affixPattern)) {
+ tag = nextToken(tag, affixPattern, status);
+ if (U_FAILURE(status)) { return false; }
+ if (tag.type < 0 && getFieldForType(tag.type) == Field(UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+UnicodeString AffixUtils::replaceType(const UnicodeString &affixPattern, AffixPatternType type,
+ char16_t replacementChar, UErrorCode &status) {
+ UnicodeString output(affixPattern); // copy
+ if (affixPattern.length() == 0) {
+ return output;
+ }
+ AffixTag tag;
+ while (hasNext(tag, affixPattern)) {
+ tag = nextToken(tag, affixPattern, status);
+ if (U_FAILURE(status)) { return output; }
+ if (tag.type == type) {
+ output.replace(tag.offset - 1, 1, replacementChar);
+ }
+ }
+ return output;
+}
+
+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.char32At(offset);
+ int32_t count = U16_LENGTH(cp);
+
+ switch (state) {
+ case STATE_BASE:
+ switch (cp) {
+ case u'\'':
+ state = STATE_FIRST_QUOTE;
+ offset += count;
+ // continue to the next code point
+ break;
+ case u'-':
+ return makeTag(offset + count, TYPE_MINUS_SIGN, STATE_BASE, 0);
+ case u'+':
+ return makeTag(offset + count, TYPE_PLUS_SIGN, STATE_BASE, 0);
+ case u'%':
+ return makeTag(offset + count, TYPE_PERCENT, STATE_BASE, 0);
+ case u'‰':
+ return makeTag(offset + count, TYPE_PERMILLE, STATE_BASE, 0);
+ case u'¤':
+ state = STATE_FIRST_CURR;
+ offset += count;
+ // continue to the next code point
+ break;
+ default:
+ return makeTag(offset + count, TYPE_CODEPOINT, STATE_BASE, cp);
+ }
+ break;
+ case STATE_FIRST_QUOTE:
+ if (cp == u'\'') {
+ return makeTag(offset + count, TYPE_CODEPOINT, STATE_BASE, cp);
+ } else {
+ return makeTag(offset + count, TYPE_CODEPOINT, STATE_INSIDE_QUOTE, cp);
+ }
+ case STATE_INSIDE_QUOTE:
+ if (cp == u'\'') {
+ state = STATE_AFTER_QUOTE;
+ offset += count;
+ // continue to the next code point
+ break;
+ } else {
+ return makeTag(offset + count, TYPE_CODEPOINT, STATE_INSIDE_QUOTE, cp);
+ }
+ case STATE_AFTER_QUOTE:
+ if (cp == u'\'') {
+ return makeTag(offset + count, TYPE_CODEPOINT, STATE_INSIDE_QUOTE, cp);
+ } else {
+ state = STATE_BASE;
+ // re-evaluate this code point
+ break;
+ }
+ case STATE_FIRST_CURR:
+ if (cp == u'¤') {
+ state = STATE_SECOND_CURR;
+ offset += count;
+ // continue to the next code point
+ break;
+ } else {
+ return makeTag(offset, TYPE_CURRENCY_SINGLE, STATE_BASE, 0);
+ }
+ case STATE_SECOND_CURR:
+ if (cp == u'¤') {
+ state = STATE_THIRD_CURR;
+ offset += count;
+ // continue to the next code point
+ break;
+ } else {
+ return makeTag(offset, TYPE_CURRENCY_DOUBLE, STATE_BASE, 0);
+ }
+ case STATE_THIRD_CURR:
+ if (cp == u'¤') {
+ state = STATE_FOURTH_CURR;
+ offset += count;
+ // continue to the next code point
+ break;
+ } else {
+ return makeTag(offset, TYPE_CURRENCY_TRIPLE, STATE_BASE, 0);
+ }
+ case STATE_FOURTH_CURR:
+ if (cp == u'¤') {
+ state = STATE_FIFTH_CURR;
+ offset += count;
+ // continue to the next code point
+ break;
+ } else {
+ return makeTag(offset, TYPE_CURRENCY_QUAD, STATE_BASE, 0);
+ }
+ case STATE_FIFTH_CURR:
+ if (cp == u'¤') {
+ state = STATE_OVERFLOW_CURR;
+ offset += count;
+ // continue to the next code point
+ break;
+ } else {
+ return makeTag(offset, TYPE_CURRENCY_QUINT, STATE_BASE, 0);
+ }
+ case STATE_OVERFLOW_CURR:
+ if (cp == u'¤') {
+ offset += count;
+ // continue to the next code point and loop back to this state
+ break;
+ } else {
+ return makeTag(offset, TYPE_CURRENCY_OVERFLOW, STATE_BASE, 0);
+ }
+ default:
+ UPRV_UNREACHABLE;
+ }
+ }
+ // End of string
+ switch (state) {
+ case STATE_BASE:
+ // No more tokens in string.
+ return {-1};
+ case STATE_FIRST_QUOTE:
+ case STATE_INSIDE_QUOTE:
+ // For consistent behavior with the JDK and ICU 58, set an error here.
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return {-1};
+ case STATE_AFTER_QUOTE:
+ // No more tokens in string.
+ return {-1};
+ case STATE_FIRST_CURR:
+ return makeTag(offset, TYPE_CURRENCY_SINGLE, STATE_BASE, 0);
+ case STATE_SECOND_CURR:
+ return makeTag(offset, TYPE_CURRENCY_DOUBLE, STATE_BASE, 0);
+ case STATE_THIRD_CURR:
+ return makeTag(offset, TYPE_CURRENCY_TRIPLE, STATE_BASE, 0);
+ case STATE_FOURTH_CURR:
+ return makeTag(offset, TYPE_CURRENCY_QUAD, STATE_BASE, 0);
+ case STATE_FIFTH_CURR:
+ return makeTag(offset, TYPE_CURRENCY_QUINT, STATE_BASE, 0);
+ case STATE_OVERFLOW_CURR:
+ return makeTag(offset, TYPE_CURRENCY_OVERFLOW, STATE_BASE, 0);
+ default:
+ UPRV_UNREACHABLE;
+ }
+}
+
+bool AffixUtils::hasNext(const AffixTag &tag, const UnicodeString &string) {
+ // First check for the {-1} and default initializer syntax.
+ if (tag.offset < 0) {
+ return false;
+ } else if (tag.offset == 0) {
+ return string.length() > 0;
+ }
+ // The rest of the fields are safe to use now.
+ // Special case: the last character in string is an end quote.
+ if (tag.state == STATE_INSIDE_QUOTE && tag.offset == string.length() - 1 &&
+ string.charAt(tag.offset) == u'\'') {
+ return false;
+ } else if (tag.state != STATE_BASE) {
+ return true;
+ } else {
+ return tag.offset < string.length();
+ }
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_affixutils.h b/contrib/libs/icu/i18n/number_affixutils.h
index 5cfde61ffd..b4948ebc00 100644
--- a/contrib/libs/icu/i18n/number_affixutils.h
+++ b/contrib/libs/icu/i18n/number_affixutils.h
@@ -1,244 +1,244 @@
-// © 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_AFFIXUTILS_H__
-#define __NUMBER_AFFIXUTILS_H__
-
-#include <cstdint>
-#include "number_types.h"
-#include "unicode/stringpiece.h"
-#include "unicode/unistr.h"
-#include "formatted_string_builder.h"
-#include "unicode/uniset.h"
-
-U_NAMESPACE_BEGIN namespace number {
-namespace impl {
-
-enum AffixPatternState {
- STATE_BASE = 0,
- STATE_FIRST_QUOTE = 1,
- STATE_INSIDE_QUOTE = 2,
- STATE_AFTER_QUOTE = 3,
- STATE_FIRST_CURR = 4,
- STATE_SECOND_CURR = 5,
- STATE_THIRD_CURR = 6,
- STATE_FOURTH_CURR = 7,
- STATE_FIFTH_CURR = 8,
- STATE_OVERFLOW_CURR = 9
-};
-
-// enum AffixPatternType defined in internals.h
-
-struct AffixTag {
- int32_t offset;
- UChar32 codePoint;
- AffixPatternState state;
- AffixPatternType type;
-
- AffixTag()
- : offset(0), state(STATE_BASE) {}
-
- AffixTag(int32_t offset)
- : offset(offset) {}
-
- AffixTag(int32_t offset, UChar32 codePoint, AffixPatternState state, AffixPatternType 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();
-
- // TODO: Could this be more efficient if it returned by reference?
- virtual UnicodeString getSymbol(AffixPatternType type) const = 0;
-};
-
-/**
- * Performs manipulations on affix patterns: the prefix and suffix strings associated with a decimal
- * format pattern. For example:
- *
- * <table>
- * <tr><th>Affix Pattern</th><th>Example Unescaped (Formatted) String</th></tr>
- * <tr><td>abc</td><td>abc</td></tr>
- * <tr><td>ab-</td><td>ab−</td></tr>
- * <tr><td>ab'-'</td><td>ab-</td></tr>
- * <tr><td>ab''</td><td>ab'</td></tr>
- * </table>
- *
- * To manually iterate over tokens in a literal string, use the following pattern, which is designed
- * to be efficient.
- *
- * <pre>
- * long tag = 0L;
- * while (AffixPatternUtils.hasNext(tag, patternString)) {
- * tag = AffixPatternUtils.nextToken(tag, patternString);
- * int typeOrCp = AffixPatternUtils.getTypeOrCp(tag);
- * switch (typeOrCp) {
- * case AffixPatternUtils.TYPE_MINUS_SIGN:
- * // Current token is a minus sign.
- * break;
- * case AffixPatternUtils.TYPE_PLUS_SIGN:
- * // Current token is a plus sign.
- * break;
- * case AffixPatternUtils.TYPE_PERCENT:
- * // Current token is a percent sign.
- * break;
- * // ... other types ...
- * default:
- * // Current token is an arbitrary code point.
- * // The variable typeOrCp is the code point.
- * break;
- * }
- * }
- * </pre>
- */
-class U_I18N_API AffixUtils {
-
- public:
-
- /**
- * Estimates the number of code points present in an unescaped version of the affix pattern string
- * (one that would be returned by {@link #unescape}), assuming that all interpolated symbols
- * consume one code point and that currencies consume as many code points as their symbol width.
- * Used for computing padding width.
- *
- * @param patternString The original string whose width will be estimated.
- * @return The length of the unescaped string.
- */
- static int32_t estimateLength(const UnicodeString& patternString, UErrorCode& status);
-
- /**
- * Takes a string and escapes (quotes) characters that have special meaning in the affix pattern
- * syntax. This function does not reverse-lookup symbols.
- *
- * <p>Example input: "-$x"; example output: "'-'$x"
- *
- * @param input The string to be escaped.
- * @return The resulting UnicodeString.
- */
- static UnicodeString escape(const UnicodeString& input);
-
- static Field getFieldForType(AffixPatternType type);
-
- /**
- * Executes the unescape state machine. Replaces the unquoted characters "-", "+", "%", "‰", and
- * "¤" with the corresponding symbols provided by the {@link SymbolProvider}, and inserts the
- * result into the FormattedStringBuilder at the requested location.
- *
- * <p>Example input: "'-'¤x"; example output: "-$x"
- *
- * @param affixPattern The original string to be unescaped.
- * @param output The FormattedStringBuilder to mutate with the result.
- * @param position The index into the FormattedStringBuilder to insert the string.
- * @param provider An object to generate locale symbols.
- */
- static int32_t unescape(const UnicodeString& affixPattern, FormattedStringBuilder& output,
- int32_t position, const SymbolProvider& provider, Field field,
- UErrorCode& status);
-
- /**
- * Sames as {@link #unescape}, but only calculates the code point count. More efficient than {@link #unescape}
- * if you only need the length but not the string itself.
- *
- * @param affixPattern The original string to be unescaped.
- * @param provider An object to generate locale symbols.
- * @return The same return value as if you called {@link #unescape}.
- */
- 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
- * one of the constants "TYPE_" in {@link AffixPatternUtils}.
- *
- * @param affixPattern The affix pattern to check.
- * @param type The token type.
- * @return true if the affix pattern contains the given token type; false otherwise.
- */
- static bool containsType(const UnicodeString& affixPattern, AffixPatternType type, UErrorCode& status);
-
- /**
- * Checks whether the specified affix pattern has any unquoted currency symbols ("¤").
- *
- * @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 UnicodeString& affixPattern, UErrorCode& status);
-
- /**
- * Replaces all occurrences of tokens with the given type with the given replacement char.
- *
- * @param affixPattern The source affix pattern (does not get modified).
- * @param type The token type.
- * @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 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.
- *
- * @param tag A bitmask used for keeping track of state from token to token. The initial value
- * should be 0L.
- * @param patternString The affix pattern.
- * @return The bitmask tag to pass to the next call of this method to retrieve the following token
- * (never negative), or -1 if there were no more tokens in the affix pattern.
- * @see #hasNext
- */
- 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
- * {@link #nextToken}.
- *
- * @param tag The bitmask tag of the previous token, as returned by {@link #nextToken}.
- * @param string The affix pattern.
- * @return true if there are more tokens to consume; false otherwise.
- */
- static bool hasNext(const AffixTag& tag, const UnicodeString& string);
-
- private:
- /**
- * Encodes the given values into a tag struct.
- * 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) {
- return {offset, cp, state, type};
- }
-};
-
-} // namespace impl
-} // namespace number
-U_NAMESPACE_END
-
-
-#endif //__NUMBER_AFFIXUTILS_H__
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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_AFFIXUTILS_H__
+#define __NUMBER_AFFIXUTILS_H__
+
+#include <cstdint>
+#include "number_types.h"
+#include "unicode/stringpiece.h"
+#include "unicode/unistr.h"
+#include "formatted_string_builder.h"
+#include "unicode/uniset.h"
+
+U_NAMESPACE_BEGIN namespace number {
+namespace impl {
+
+enum AffixPatternState {
+ STATE_BASE = 0,
+ STATE_FIRST_QUOTE = 1,
+ STATE_INSIDE_QUOTE = 2,
+ STATE_AFTER_QUOTE = 3,
+ STATE_FIRST_CURR = 4,
+ STATE_SECOND_CURR = 5,
+ STATE_THIRD_CURR = 6,
+ STATE_FOURTH_CURR = 7,
+ STATE_FIFTH_CURR = 8,
+ STATE_OVERFLOW_CURR = 9
+};
+
+// enum AffixPatternType defined in internals.h
+
+struct AffixTag {
+ int32_t offset;
+ UChar32 codePoint;
+ AffixPatternState state;
+ AffixPatternType type;
+
+ AffixTag()
+ : offset(0), state(STATE_BASE) {}
+
+ AffixTag(int32_t offset)
+ : offset(offset) {}
+
+ AffixTag(int32_t offset, UChar32 codePoint, AffixPatternState state, AffixPatternType 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();
+
+ // TODO: Could this be more efficient if it returned by reference?
+ virtual UnicodeString getSymbol(AffixPatternType type) const = 0;
+};
+
+/**
+ * Performs manipulations on affix patterns: the prefix and suffix strings associated with a decimal
+ * format pattern. For example:
+ *
+ * <table>
+ * <tr><th>Affix Pattern</th><th>Example Unescaped (Formatted) String</th></tr>
+ * <tr><td>abc</td><td>abc</td></tr>
+ * <tr><td>ab-</td><td>ab−</td></tr>
+ * <tr><td>ab'-'</td><td>ab-</td></tr>
+ * <tr><td>ab''</td><td>ab'</td></tr>
+ * </table>
+ *
+ * To manually iterate over tokens in a literal string, use the following pattern, which is designed
+ * to be efficient.
+ *
+ * <pre>
+ * long tag = 0L;
+ * while (AffixPatternUtils.hasNext(tag, patternString)) {
+ * tag = AffixPatternUtils.nextToken(tag, patternString);
+ * int typeOrCp = AffixPatternUtils.getTypeOrCp(tag);
+ * switch (typeOrCp) {
+ * case AffixPatternUtils.TYPE_MINUS_SIGN:
+ * // Current token is a minus sign.
+ * break;
+ * case AffixPatternUtils.TYPE_PLUS_SIGN:
+ * // Current token is a plus sign.
+ * break;
+ * case AffixPatternUtils.TYPE_PERCENT:
+ * // Current token is a percent sign.
+ * break;
+ * // ... other types ...
+ * default:
+ * // Current token is an arbitrary code point.
+ * // The variable typeOrCp is the code point.
+ * break;
+ * }
+ * }
+ * </pre>
+ */
+class U_I18N_API AffixUtils {
+
+ public:
+
+ /**
+ * Estimates the number of code points present in an unescaped version of the affix pattern string
+ * (one that would be returned by {@link #unescape}), assuming that all interpolated symbols
+ * consume one code point and that currencies consume as many code points as their symbol width.
+ * Used for computing padding width.
+ *
+ * @param patternString The original string whose width will be estimated.
+ * @return The length of the unescaped string.
+ */
+ static int32_t estimateLength(const UnicodeString& patternString, UErrorCode& status);
+
+ /**
+ * Takes a string and escapes (quotes) characters that have special meaning in the affix pattern
+ * syntax. This function does not reverse-lookup symbols.
+ *
+ * <p>Example input: "-$x"; example output: "'-'$x"
+ *
+ * @param input The string to be escaped.
+ * @return The resulting UnicodeString.
+ */
+ static UnicodeString escape(const UnicodeString& input);
+
+ static Field getFieldForType(AffixPatternType type);
+
+ /**
+ * Executes the unescape state machine. Replaces the unquoted characters "-", "+", "%", "‰", and
+ * "¤" with the corresponding symbols provided by the {@link SymbolProvider}, and inserts the
+ * result into the FormattedStringBuilder at the requested location.
+ *
+ * <p>Example input: "'-'¤x"; example output: "-$x"
+ *
+ * @param affixPattern The original string to be unescaped.
+ * @param output The FormattedStringBuilder to mutate with the result.
+ * @param position The index into the FormattedStringBuilder to insert the string.
+ * @param provider An object to generate locale symbols.
+ */
+ static int32_t unescape(const UnicodeString& affixPattern, FormattedStringBuilder& output,
+ int32_t position, const SymbolProvider& provider, Field field,
+ UErrorCode& status);
+
+ /**
+ * Sames as {@link #unescape}, but only calculates the code point count. More efficient than {@link #unescape}
+ * if you only need the length but not the string itself.
+ *
+ * @param affixPattern The original string to be unescaped.
+ * @param provider An object to generate locale symbols.
+ * @return The same return value as if you called {@link #unescape}.
+ */
+ 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
+ * one of the constants "TYPE_" in {@link AffixPatternUtils}.
+ *
+ * @param affixPattern The affix pattern to check.
+ * @param type The token type.
+ * @return true if the affix pattern contains the given token type; false otherwise.
+ */
+ static bool containsType(const UnicodeString& affixPattern, AffixPatternType type, UErrorCode& status);
+
+ /**
+ * Checks whether the specified affix pattern has any unquoted currency symbols ("¤").
+ *
+ * @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 UnicodeString& affixPattern, UErrorCode& status);
+
+ /**
+ * Replaces all occurrences of tokens with the given type with the given replacement char.
+ *
+ * @param affixPattern The source affix pattern (does not get modified).
+ * @param type The token type.
+ * @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 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.
+ *
+ * @param tag A bitmask used for keeping track of state from token to token. The initial value
+ * should be 0L.
+ * @param patternString The affix pattern.
+ * @return The bitmask tag to pass to the next call of this method to retrieve the following token
+ * (never negative), or -1 if there were no more tokens in the affix pattern.
+ * @see #hasNext
+ */
+ 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
+ * {@link #nextToken}.
+ *
+ * @param tag The bitmask tag of the previous token, as returned by {@link #nextToken}.
+ * @param string The affix pattern.
+ * @return true if there are more tokens to consume; false otherwise.
+ */
+ static bool hasNext(const AffixTag& tag, const UnicodeString& string);
+
+ private:
+ /**
+ * Encodes the given values into a tag struct.
+ * 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) {
+ return {offset, cp, state, type};
+ }
+};
+
+} // namespace impl
+} // namespace number
+U_NAMESPACE_END
+
+
+#endif //__NUMBER_AFFIXUTILS_H__
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_asformat.cpp b/contrib/libs/icu/i18n/number_asformat.cpp
index 9d10d1f558..31df5740b7 100644
--- a/contrib/libs/icu/i18n/number_asformat.cpp
+++ b/contrib/libs/icu/i18n/number_asformat.cpp
@@ -1,117 +1,117 @@
-// © 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 <stdlib.h>
-#include <cmath>
-#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<const LocalizedNumberFormatterAsFormat*>(&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);
-}
-
-LocalizedNumberFormatterAsFormat* 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.nextFieldPosition(pos, status);
- if (found && appendTo.length() != 0) {
- pos.setBeginIndex(pos.getBeginIndex() + appendTo.length());
- pos.setEndIndex(pos.getEndIndex() + appendTo.length());
- }
- appendTo.append(data.toTempString(status));
- 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.toTempString(status));
- if (posIter != nullptr) {
- FieldPositionIteratorHandler fpih(posIter, status);
- data.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;
-}
-
-
-// Definitions of public API methods (put here for dependency disentanglement)
-
-Format* LocalizedNumberFormatter::toFormat(UErrorCode& status) const {
- if (U_FAILURE(status)) {
- return nullptr;
- }
- LocalPointer<LocalizedNumberFormatterAsFormat> retval(
- new LocalizedNumberFormatterAsFormat(*this, fMacros.locale), status);
- return retval.orphan();
-}
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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 <stdlib.h>
+#include <cmath>
+#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<const LocalizedNumberFormatterAsFormat*>(&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);
+}
+
+LocalizedNumberFormatterAsFormat* 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.nextFieldPosition(pos, status);
+ if (found && appendTo.length() != 0) {
+ pos.setBeginIndex(pos.getBeginIndex() + appendTo.length());
+ pos.setEndIndex(pos.getEndIndex() + appendTo.length());
+ }
+ appendTo.append(data.toTempString(status));
+ 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.toTempString(status));
+ if (posIter != nullptr) {
+ FieldPositionIteratorHandler fpih(posIter, status);
+ data.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;
+}
+
+
+// Definitions of public API methods (put here for dependency disentanglement)
+
+Format* LocalizedNumberFormatter::toFormat(UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ LocalPointer<LocalizedNumberFormatterAsFormat> retval(
+ new LocalizedNumberFormatterAsFormat(*this, fMacros.locale), status);
+ return retval.orphan();
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_asformat.h b/contrib/libs/icu/i18n/number_asformat.h
index 7b0a1dee6f..64f5504cfe 100644
--- a/contrib/libs/icu/i18n/number_asformat.h
+++ b/contrib/libs/icu/i18n/number_asformat.h
@@ -1,107 +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.
- */
- LocalizedNumberFormatterAsFormat* 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:
- *
- * <pre>
- * LocalizedNumberFormatter localFormatter = fmt->getNumberFormatter();
- * </pre>
- *
- * You can however use the return value directly when chaining:
- *
- * <pre>
- * FormattedNumber result = fmt->getNumberFormatter().formatDouble(514.23, status);
- * </pre>
- *
- * @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 */
+// © 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.
+ */
+ LocalizedNumberFormatterAsFormat* 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:
+ *
+ * <pre>
+ * LocalizedNumberFormatter localFormatter = fmt->getNumberFormatter();
+ * </pre>
+ *
+ * You can however use the return value directly when chaining:
+ *
+ * <pre>
+ * FormattedNumber result = fmt->getNumberFormatter().formatDouble(514.23, status);
+ * </pre>
+ *
+ * @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/contrib/libs/icu/i18n/number_capi.cpp b/contrib/libs/icu/i18n/number_capi.cpp
index 21a600d6ab..3794bfcf5d 100644
--- a/contrib/libs/icu/i18n/number_capi.cpp
+++ b/contrib/libs/icu/i18n/number_capi.cpp
@@ -1,234 +1,234 @@
-// © 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 "formattedval_impl.h"
-#include "unicode/numberformatter.h"
-#include "unicode/unumberformatter.h"
-
-using namespace icu;
-using namespace icu::number;
-using namespace icu::number::impl;
-
-
-U_NAMESPACE_BEGIN
-namespace number {
-namespace impl {
-
-/**
- * Implementation class for UNumberFormatter. Wraps a LocalizedNumberFormatter.
- */
-struct UNumberFormatterData : public UMemory,
- // Magic number as ASCII == "NFR" (NumberFormatteR)
- public IcuCApiHelper<UNumberFormatter, UNumberFormatterData, 0x4E465200> {
- LocalizedNumberFormatter fFormatter;
-};
-
-struct UFormattedNumberImpl;
-
-// Magic number as ASCII == "FDN" (FormatteDNumber)
-typedef IcuCApiHelper<UFormattedNumber, UFormattedNumberImpl, 0x46444E00> UFormattedNumberApiHelper;
-
-struct UFormattedNumberImpl : public UFormattedValueImpl, public UFormattedNumberApiHelper {
- UFormattedNumberImpl();
- ~UFormattedNumberImpl();
-
- FormattedNumber fImpl;
- UFormattedNumberData fData;
-};
-
-UFormattedNumberImpl::UFormattedNumberImpl()
- : fImpl(&fData) {
- fFormattedValue = &fImpl;
-}
-
-UFormattedNumberImpl::~UFormattedNumberImpl() {
- // Disown the data from fImpl so it doesn't get deleted twice
- fImpl.fData = nullptr;
-}
-
-}
-}
-U_NAMESPACE_END
-
-
-UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(
- UFormattedNumber,
- UFormattedNumberImpl,
- UFormattedNumberApiHelper,
- unumf)
-
-
-const DecimalQuantity* icu::number::impl::validateUFormattedNumberToDecimalQuantity(
- const UFormattedNumber* uresult, UErrorCode& status) {
- auto* result = UFormattedNumberApiHelper::validate(uresult, status);
- if (U_FAILURE(status)) {
- return nullptr;
- }
- return &result->fData.quantity;
-}
-
-
-
-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 UNumberFormatter* U_EXPORT2
-unumf_openForSkeletonAndLocaleWithError(const UChar* skeleton, int32_t skeletonLen, const char* locale,
- UParseError* perror, 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, *perror, *ec).locale(locale);
- 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);
- auto* result = UFormattedNumberApiHelper::validate(uresult, *ec);
- if (U_FAILURE(*ec)) { return; }
-
- result->fData.getStringRef().clear();
- result->fData.quantity.setToLong(value);
- formatter->fFormatter.formatImpl(&result->fData, *ec);
-}
-
-U_CAPI void U_EXPORT2
-unumf_formatDouble(const UNumberFormatter* uformatter, double value, UFormattedNumber* uresult,
- UErrorCode* ec) {
- const UNumberFormatterData* formatter = UNumberFormatterData::validate(uformatter, *ec);
- auto* result = UFormattedNumberApiHelper::validate(uresult, *ec);
- if (U_FAILURE(*ec)) { return; }
-
- result->fData.getStringRef().clear();
- result->fData.quantity.setToDouble(value);
- formatter->fFormatter.formatImpl(&result->fData, *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);
- auto* result = UFormattedNumberApiHelper::validate(uresult, *ec);
- if (U_FAILURE(*ec)) { return; }
-
- result->fData.getStringRef().clear();
- result->fData.quantity.setToDecNumber({value, valueLen}, *ec);
- if (U_FAILURE(*ec)) { return; }
- formatter->fFormatter.formatImpl(&result->fData, *ec);
-}
-
-U_CAPI int32_t U_EXPORT2
-unumf_resultToString(const UFormattedNumber* uresult, UChar* buffer, int32_t bufferCapacity,
- UErrorCode* ec) {
- const auto* result = UFormattedNumberApiHelper::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->fData.toTempString(*ec).extract(buffer, bufferCapacity, *ec);
-}
-
-U_CAPI UBool U_EXPORT2
-unumf_resultNextFieldPosition(const UFormattedNumber* uresult, UFieldPosition* ufpos, UErrorCode* ec) {
- const auto* result = UFormattedNumberApiHelper::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->fData.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 auto* result = UFormattedNumberApiHelper::validate(uresult, *ec);
- if (U_FAILURE(*ec)) { return; }
-
- if (ufpositer == nullptr) {
- *ec = U_ILLEGAL_ARGUMENT_ERROR;
- return;
- }
-
- auto* fpi = reinterpret_cast<FieldPositionIterator*>(ufpositer);
- FieldPositionIteratorHandler fpih(fpi, *ec);
- result->fData.getAllFieldPositions(fpih, *ec);
-}
-
-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 */
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+// © 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 "formattedval_impl.h"
+#include "unicode/numberformatter.h"
+#include "unicode/unumberformatter.h"
+
+using namespace icu;
+using namespace icu::number;
+using namespace icu::number::impl;
+
+
+U_NAMESPACE_BEGIN
+namespace number {
+namespace impl {
+
+/**
+ * Implementation class for UNumberFormatter. Wraps a LocalizedNumberFormatter.
+ */
+struct UNumberFormatterData : public UMemory,
+ // Magic number as ASCII == "NFR" (NumberFormatteR)
+ public IcuCApiHelper<UNumberFormatter, UNumberFormatterData, 0x4E465200> {
+ LocalizedNumberFormatter fFormatter;
+};
+
+struct UFormattedNumberImpl;
+
+// Magic number as ASCII == "FDN" (FormatteDNumber)
+typedef IcuCApiHelper<UFormattedNumber, UFormattedNumberImpl, 0x46444E00> UFormattedNumberApiHelper;
+
+struct UFormattedNumberImpl : public UFormattedValueImpl, public UFormattedNumberApiHelper {
+ UFormattedNumberImpl();
+ ~UFormattedNumberImpl();
+
+ FormattedNumber fImpl;
+ UFormattedNumberData fData;
+};
+
+UFormattedNumberImpl::UFormattedNumberImpl()
+ : fImpl(&fData) {
+ fFormattedValue = &fImpl;
+}
+
+UFormattedNumberImpl::~UFormattedNumberImpl() {
+ // Disown the data from fImpl so it doesn't get deleted twice
+ fImpl.fData = nullptr;
+}
+
+}
+}
+U_NAMESPACE_END
+
+
+UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL(
+ UFormattedNumber,
+ UFormattedNumberImpl,
+ UFormattedNumberApiHelper,
+ unumf)
+
+
+const DecimalQuantity* icu::number::impl::validateUFormattedNumberToDecimalQuantity(
+ const UFormattedNumber* uresult, UErrorCode& status) {
+ auto* result = UFormattedNumberApiHelper::validate(uresult, status);
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ return &result->fData.quantity;
+}
+
+
+
+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 UNumberFormatter* U_EXPORT2
+unumf_openForSkeletonAndLocaleWithError(const UChar* skeleton, int32_t skeletonLen, const char* locale,
+ UParseError* perror, 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, *perror, *ec).locale(locale);
+ 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);
+ auto* result = UFormattedNumberApiHelper::validate(uresult, *ec);
+ if (U_FAILURE(*ec)) { return; }
+
+ result->fData.getStringRef().clear();
+ result->fData.quantity.setToLong(value);
+ formatter->fFormatter.formatImpl(&result->fData, *ec);
+}
+
+U_CAPI void U_EXPORT2
+unumf_formatDouble(const UNumberFormatter* uformatter, double value, UFormattedNumber* uresult,
+ UErrorCode* ec) {
+ const UNumberFormatterData* formatter = UNumberFormatterData::validate(uformatter, *ec);
+ auto* result = UFormattedNumberApiHelper::validate(uresult, *ec);
+ if (U_FAILURE(*ec)) { return; }
+
+ result->fData.getStringRef().clear();
+ result->fData.quantity.setToDouble(value);
+ formatter->fFormatter.formatImpl(&result->fData, *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);
+ auto* result = UFormattedNumberApiHelper::validate(uresult, *ec);
+ if (U_FAILURE(*ec)) { return; }
+
+ result->fData.getStringRef().clear();
+ result->fData.quantity.setToDecNumber({value, valueLen}, *ec);
+ if (U_FAILURE(*ec)) { return; }
+ formatter->fFormatter.formatImpl(&result->fData, *ec);
+}
+
+U_CAPI int32_t U_EXPORT2
+unumf_resultToString(const UFormattedNumber* uresult, UChar* buffer, int32_t bufferCapacity,
+ UErrorCode* ec) {
+ const auto* result = UFormattedNumberApiHelper::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->fData.toTempString(*ec).extract(buffer, bufferCapacity, *ec);
+}
+
+U_CAPI UBool U_EXPORT2
+unumf_resultNextFieldPosition(const UFormattedNumber* uresult, UFieldPosition* ufpos, UErrorCode* ec) {
+ const auto* result = UFormattedNumberApiHelper::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->fData.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 auto* result = UFormattedNumberApiHelper::validate(uresult, *ec);
+ if (U_FAILURE(*ec)) { return; }
+
+ if (ufpositer == nullptr) {
+ *ec = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ auto* fpi = reinterpret_cast<FieldPositionIterator*>(ufpositer);
+ FieldPositionIteratorHandler fpih(fpi, *ec);
+ result->fData.getAllFieldPositions(fpih, *ec);
+}
+
+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/contrib/libs/icu/i18n/number_compact.cpp b/contrib/libs/icu/i18n/number_compact.cpp
index e1fef8feb5..34d6006db2 100644
--- a/contrib/libs/icu/i18n/number_compact.cpp
+++ b/contrib/libs/icu/i18n/number_compact.cpp
@@ -1,335 +1,335 @@
-// © 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
-
-#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;
-using namespace icu::number;
-using namespace icu::number::impl;
-
-namespace {
-
-// A dummy object used when a "0" compact decimal entry is encountered. This is necessary
-// in order to prevent falling back to root. Object equality ("==") is intended.
-const UChar *USE_FALLBACK = u"<USE FALLBACK>";
-
-/** Produces a string like "NumberElements/latn/patternsShort/decimalFormat". */
-void getResourceBundleKey(const char *nsName, CompactStyle compactStyle, CompactType compactType,
- CharString &sb, UErrorCode &status) {
- sb.clear();
- sb.append("NumberElements/", status);
- sb.append(nsName, status);
- sb.append(compactStyle == CompactStyle::UNUM_SHORT ? "/patternsShort" : "/patternsLong", status);
- sb.append(compactType == CompactType::TYPE_DECIMAL ? "/decimalFormat" : "/currencyFormat", status);
-}
-
-int32_t getIndex(int32_t magnitude, StandardPlural::Form plural) {
- return magnitude * StandardPlural::COUNT + plural;
-}
-
-int32_t countZeros(const UChar *patternString, int32_t patternLength) {
- // NOTE: This strategy for computing the number of zeros is a hack for efficiency.
- // It could break if there are any 0s that aren't part of the main pattern.
- int32_t numZeros = 0;
- for (int32_t i = 0; i < patternLength; i++) {
- if (patternString[i] == u'0') {
- numZeros++;
- } else if (numZeros > 0) {
- break; // zeros should always be contiguous
- }
- }
- return numZeros;
-}
-
-} // namespace
-
-// NOTE: patterns and multipliers both get zero-initialized.
-CompactData::CompactData() : patterns(), multipliers(), largestMagnitude(0), isEmpty(TRUE) {
-}
-
-void CompactData::populate(const Locale &locale, const char *nsName, CompactStyle compactStyle,
- CompactType compactType, UErrorCode &status) {
- CompactDataSink sink(*this);
- LocalUResourceBundlePointer rb(ures_open(nullptr, locale.getName(), &status));
- if (U_FAILURE(status)) { return; }
-
- bool nsIsLatn = strcmp(nsName, "latn") == 0;
- bool compactIsShort = compactStyle == CompactStyle::UNUM_SHORT;
-
- // Fall back to latn numbering system and/or short compact style.
- CharString resourceKey;
- getResourceBundleKey(nsName, compactStyle, compactType, resourceKey, status);
- UErrorCode localStatus = U_ZERO_ERROR;
- ures_getAllItemsWithFallback(rb.getAlias(), resourceKey.data(), sink, localStatus);
- if (isEmpty && !nsIsLatn) {
- getResourceBundleKey("latn", compactStyle, compactType, resourceKey, status);
- localStatus = U_ZERO_ERROR;
- ures_getAllItemsWithFallback(rb.getAlias(), resourceKey.data(), sink, localStatus);
- }
- if (isEmpty && !compactIsShort) {
- getResourceBundleKey(nsName, CompactStyle::UNUM_SHORT, compactType, resourceKey, status);
- localStatus = U_ZERO_ERROR;
- ures_getAllItemsWithFallback(rb.getAlias(), resourceKey.data(), sink, localStatus);
- }
- if (isEmpty && !nsIsLatn && !compactIsShort) {
- getResourceBundleKey("latn", CompactStyle::UNUM_SHORT, compactType, resourceKey, status);
- localStatus = U_ZERO_ERROR;
- ures_getAllItemsWithFallback(rb.getAlias(), resourceKey.data(), sink, localStatus);
- }
-
- // The last fallback should be guaranteed to return data.
- if (isEmpty) {
- status = U_INTERNAL_PROGRAM_ERROR;
- }
-}
-
-int32_t CompactData::getMultiplier(int32_t magnitude) const {
- if (magnitude < 0) {
- return 0;
- }
- if (magnitude > largestMagnitude) {
- magnitude = largestMagnitude;
- }
- return multipliers[magnitude];
-}
-
-const UChar *CompactData::getPattern(int32_t magnitude, StandardPlural::Form plural) const {
- if (magnitude < 0) {
- return nullptr;
- }
- if (magnitude > largestMagnitude) {
- magnitude = largestMagnitude;
- }
- const UChar *patternString = patterns[getIndex(magnitude, plural)];
- if (patternString == nullptr && plural != StandardPlural::OTHER) {
- // Fall back to "other" plural variant
- patternString = patterns[getIndex(magnitude, StandardPlural::OTHER)];
- }
- if (patternString == USE_FALLBACK) { // == is intended
- // Return null if USE_FALLBACK is present
- patternString = nullptr;
- }
- return patternString;
-}
-
-void CompactData::getUniquePatterns(UVector &output, UErrorCode &status) const {
- U_ASSERT(output.isEmpty());
- // NOTE: In C++, this is done more manually with a UVector.
- // In Java, we can take advantage of JDK HashSet.
- for (auto pattern : patterns) {
- if (pattern == nullptr || pattern == USE_FALLBACK) {
- continue;
- }
-
- // Insert pattern into the UVector if the UVector does not already contain the pattern.
- // Search the UVector from the end since identical patterns are likely to be adjacent.
- for (int32_t i = output.size() - 1; i >= 0; i--) {
- if (u_strcmp(pattern, static_cast<const UChar *>(output[i])) == 0) {
- goto continue_outer;
- }
- }
-
- // The string was not found; add it to the UVector.
- // ANDY: This requires a const_cast. Why?
- output.addElement(const_cast<UChar *>(pattern), status);
-
- continue_outer:
- continue;
- }
-}
-
-void CompactData::CompactDataSink::put(const char *key, ResourceValue &value, UBool /*noFallback*/,
- UErrorCode &status) {
- // traverse into the table of powers of ten
- ResourceTable powersOfTenTable = value.getTable(status);
- if (U_FAILURE(status)) { return; }
- for (int i3 = 0; powersOfTenTable.getKeyAndValue(i3, key, value); ++i3) {
-
- // Assumes that the keys are always of the form "10000" where the magnitude is the
- // length of the key minus one. We expect magnitudes to be less than MAX_DIGITS.
- auto magnitude = static_cast<int8_t> (strlen(key) - 1);
- int8_t multiplier = data.multipliers[magnitude];
- U_ASSERT(magnitude < COMPACT_MAX_DIGITS);
-
- // Iterate over the plural variants ("one", "other", etc)
- ResourceTable pluralVariantsTable = value.getTable(status);
- if (U_FAILURE(status)) { return; }
- for (int i4 = 0; pluralVariantsTable.getKeyAndValue(i4, key, value); ++i4) {
-
- // Skip this magnitude/plural if we already have it from a child locale.
- // Note: This also skips USE_FALLBACK entries.
- StandardPlural::Form plural = StandardPlural::fromString(key, status);
- if (U_FAILURE(status)) { return; }
- if (data.patterns[getIndex(magnitude, plural)] != nullptr) {
- continue;
- }
-
- // The value "0" means that we need to use the default pattern and not fall back
- // to parent locales. Example locale where this is relevant: 'it'.
- int32_t patternLength;
- const UChar *patternString = value.getString(patternLength, status);
- if (U_FAILURE(status)) { return; }
- if (u_strcmp(patternString, u"0") == 0) {
- patternString = USE_FALLBACK;
- patternLength = 0;
- }
-
- // Save the pattern string. We will parse it lazily.
- data.patterns[getIndex(magnitude, plural)] = patternString;
-
- // If necessary, compute the multiplier: the difference between the magnitude
- // and the number of zeros in the pattern.
- if (multiplier == 0) {
- int32_t numZeros = countZeros(patternString, patternLength);
- if (numZeros > 0) { // numZeros==0 in certain cases, like Somali "Kun"
- multiplier = static_cast<int8_t> (numZeros - magnitude - 1);
- }
- }
- }
-
- // Save the multiplier.
- if (data.multipliers[magnitude] == 0) {
- data.multipliers[magnitude] = multiplier;
- if (magnitude > data.largestMagnitude) {
- data.largestMagnitude = magnitude;
- }
- data.isEmpty = false;
- } else {
- U_ASSERT(data.multipliers[magnitude] == multiplier);
- }
- }
-}
-
-///////////////////////////////////////////////////////////
-/// END OF CompactData.java; BEGIN CompactNotation.java ///
-///////////////////////////////////////////////////////////
-
-CompactHandler::CompactHandler(
- CompactStyle compactStyle,
- const Locale &locale,
- const char *nsName,
- CompactType compactType,
- const PluralRules *rules,
- MutablePatternModifier *buildReference,
- bool safe,
- const MicroPropsGenerator *parent,
- UErrorCode &status)
- : rules(rules), parent(parent), safe(safe) {
- data.populate(locale, nsName, compactStyle, compactType, status);
- if (safe) {
- // Safe code path
- precomputeAllModifiers(*buildReference, status);
- } else {
- // Unsafe code path
- // Store the MutablePatternModifier reference.
- unsafePatternModifier = buildReference;
- }
-}
-
-CompactHandler::~CompactHandler() {
- for (int32_t i = 0; i < precomputedModsLength; i++) {
- delete precomputedMods[i].mod;
- }
-}
-
-void CompactHandler::precomputeAllModifiers(MutablePatternModifier &buildReference, UErrorCode &status) {
- if (U_FAILURE(status)) { return; }
-
- // Initial capacity of 12 for 0K, 00K, 000K, ...M, ...B, and ...T
- UVector allPatterns(12, status);
- if (U_FAILURE(status)) { return; }
- data.getUniquePatterns(allPatterns, status);
- if (U_FAILURE(status)) { return; }
-
- // C++ only: ensure that precomputedMods has room.
- precomputedModsLength = allPatterns.size();
- if (precomputedMods.getCapacity() < precomputedModsLength) {
- precomputedMods.resize(allPatterns.size(), status);
- if (U_FAILURE(status)) { return; }
- }
-
- for (int32_t i = 0; i < precomputedModsLength; i++) {
- auto patternString = static_cast<const UChar *>(allPatterns[i]);
- UnicodeString hello(patternString);
- CompactModInfo &info = precomputedMods[i];
- ParsedPatternInfo patternInfo;
- PatternParser::parseToPatternInfo(UnicodeString(patternString), patternInfo, status);
- if (U_FAILURE(status)) { return; }
- buildReference.setPatternInfo(&patternInfo, {UFIELD_CATEGORY_NUMBER, UNUM_COMPACT_FIELD});
- info.mod = buildReference.createImmutable(status);
- if (U_FAILURE(status)) { return; }
- info.patternString = patternString;
- }
-}
-
-void CompactHandler::processQuantity(DecimalQuantity &quantity, MicroProps &micros,
- UErrorCode &status) const {
- parent->processQuantity(quantity, micros, status);
- if (U_FAILURE(status)) { return; }
-
- // Treat zero, NaN, and infinity as if they had magnitude 0
- int32_t magnitude;
- int32_t multiplier = 0;
- if (quantity.isZeroish()) {
- magnitude = 0;
- micros.rounder.apply(quantity, status);
- } else {
- // TODO: Revisit chooseMultiplierAndApply
- multiplier = micros.rounder.chooseMultiplierAndApply(quantity, data, status);
- magnitude = quantity.isZeroish() ? 0 : quantity.getMagnitude();
- magnitude -= multiplier;
- }
-
- StandardPlural::Form plural = utils::getStandardPlural(rules, quantity);
- const UChar *patternString = data.getPattern(magnitude, plural);
- if (patternString == nullptr) {
- // Use the default (non-compact) modifier.
- // No need to take any action.
- } else if (safe) {
- // Safe code path.
- // Java uses a hash set here for O(1) lookup. C++ uses a linear search.
- // TODO: Benchmark this and maybe change to a binary search or hash table.
- int32_t i = 0;
- for (; i < precomputedModsLength; i++) {
- const CompactModInfo &info = precomputedMods[i];
- if (u_strcmp(patternString, info.patternString) == 0) {
- info.mod->applyToMicros(micros, quantity, status);
- break;
- }
- }
- // It should be guaranteed that we found the entry.
- U_ASSERT(i < precomputedModsLength);
- } else {
- // Unsafe code path.
- // Overwrite the PatternInfo in the existing modMiddle.
- // C++ Note: Use unsafePatternInfo for proper lifecycle.
- ParsedPatternInfo &patternInfo = const_cast<CompactHandler *>(this)->unsafePatternInfo;
- PatternParser::parseToPatternInfo(UnicodeString(patternString), patternInfo, status);
- unsafePatternModifier->setPatternInfo(
- &unsafePatternInfo,
- {UFIELD_CATEGORY_NUMBER, UNUM_COMPACT_FIELD});
- unsafePatternModifier->setNumberProperties(quantity.signum(), StandardPlural::Form::COUNT);
- micros.modMiddle = unsafePatternModifier;
- }
-
- // Change the exponent only after we select appropriate plural form
- // for formatting purposes so that we preserve expected formatted
- // string behavior.
- quantity.adjustExponent(-1 * multiplier);
-
- // We already performed rounding. Do not perform it again.
- micros.rounder = RoundingImpl::passThrough();
-}
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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
+
+#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;
+using namespace icu::number;
+using namespace icu::number::impl;
+
+namespace {
+
+// A dummy object used when a "0" compact decimal entry is encountered. This is necessary
+// in order to prevent falling back to root. Object equality ("==") is intended.
+const UChar *USE_FALLBACK = u"<USE FALLBACK>";
+
+/** Produces a string like "NumberElements/latn/patternsShort/decimalFormat". */
+void getResourceBundleKey(const char *nsName, CompactStyle compactStyle, CompactType compactType,
+ CharString &sb, UErrorCode &status) {
+ sb.clear();
+ sb.append("NumberElements/", status);
+ sb.append(nsName, status);
+ sb.append(compactStyle == CompactStyle::UNUM_SHORT ? "/patternsShort" : "/patternsLong", status);
+ sb.append(compactType == CompactType::TYPE_DECIMAL ? "/decimalFormat" : "/currencyFormat", status);
+}
+
+int32_t getIndex(int32_t magnitude, StandardPlural::Form plural) {
+ return magnitude * StandardPlural::COUNT + plural;
+}
+
+int32_t countZeros(const UChar *patternString, int32_t patternLength) {
+ // NOTE: This strategy for computing the number of zeros is a hack for efficiency.
+ // It could break if there are any 0s that aren't part of the main pattern.
+ int32_t numZeros = 0;
+ for (int32_t i = 0; i < patternLength; i++) {
+ if (patternString[i] == u'0') {
+ numZeros++;
+ } else if (numZeros > 0) {
+ break; // zeros should always be contiguous
+ }
+ }
+ return numZeros;
+}
+
+} // namespace
+
+// NOTE: patterns and multipliers both get zero-initialized.
+CompactData::CompactData() : patterns(), multipliers(), largestMagnitude(0), isEmpty(TRUE) {
+}
+
+void CompactData::populate(const Locale &locale, const char *nsName, CompactStyle compactStyle,
+ CompactType compactType, UErrorCode &status) {
+ CompactDataSink sink(*this);
+ LocalUResourceBundlePointer rb(ures_open(nullptr, locale.getName(), &status));
+ if (U_FAILURE(status)) { return; }
+
+ bool nsIsLatn = strcmp(nsName, "latn") == 0;
+ bool compactIsShort = compactStyle == CompactStyle::UNUM_SHORT;
+
+ // Fall back to latn numbering system and/or short compact style.
+ CharString resourceKey;
+ getResourceBundleKey(nsName, compactStyle, compactType, resourceKey, status);
+ UErrorCode localStatus = U_ZERO_ERROR;
+ ures_getAllItemsWithFallback(rb.getAlias(), resourceKey.data(), sink, localStatus);
+ if (isEmpty && !nsIsLatn) {
+ getResourceBundleKey("latn", compactStyle, compactType, resourceKey, status);
+ localStatus = U_ZERO_ERROR;
+ ures_getAllItemsWithFallback(rb.getAlias(), resourceKey.data(), sink, localStatus);
+ }
+ if (isEmpty && !compactIsShort) {
+ getResourceBundleKey(nsName, CompactStyle::UNUM_SHORT, compactType, resourceKey, status);
+ localStatus = U_ZERO_ERROR;
+ ures_getAllItemsWithFallback(rb.getAlias(), resourceKey.data(), sink, localStatus);
+ }
+ if (isEmpty && !nsIsLatn && !compactIsShort) {
+ getResourceBundleKey("latn", CompactStyle::UNUM_SHORT, compactType, resourceKey, status);
+ localStatus = U_ZERO_ERROR;
+ ures_getAllItemsWithFallback(rb.getAlias(), resourceKey.data(), sink, localStatus);
+ }
+
+ // The last fallback should be guaranteed to return data.
+ if (isEmpty) {
+ status = U_INTERNAL_PROGRAM_ERROR;
+ }
+}
+
+int32_t CompactData::getMultiplier(int32_t magnitude) const {
+ if (magnitude < 0) {
+ return 0;
+ }
+ if (magnitude > largestMagnitude) {
+ magnitude = largestMagnitude;
+ }
+ return multipliers[magnitude];
+}
+
+const UChar *CompactData::getPattern(int32_t magnitude, StandardPlural::Form plural) const {
+ if (magnitude < 0) {
+ return nullptr;
+ }
+ if (magnitude > largestMagnitude) {
+ magnitude = largestMagnitude;
+ }
+ const UChar *patternString = patterns[getIndex(magnitude, plural)];
+ if (patternString == nullptr && plural != StandardPlural::OTHER) {
+ // Fall back to "other" plural variant
+ patternString = patterns[getIndex(magnitude, StandardPlural::OTHER)];
+ }
+ if (patternString == USE_FALLBACK) { // == is intended
+ // Return null if USE_FALLBACK is present
+ patternString = nullptr;
+ }
+ return patternString;
+}
+
+void CompactData::getUniquePatterns(UVector &output, UErrorCode &status) const {
+ U_ASSERT(output.isEmpty());
+ // NOTE: In C++, this is done more manually with a UVector.
+ // In Java, we can take advantage of JDK HashSet.
+ for (auto pattern : patterns) {
+ if (pattern == nullptr || pattern == USE_FALLBACK) {
+ continue;
+ }
+
+ // Insert pattern into the UVector if the UVector does not already contain the pattern.
+ // Search the UVector from the end since identical patterns are likely to be adjacent.
+ for (int32_t i = output.size() - 1; i >= 0; i--) {
+ if (u_strcmp(pattern, static_cast<const UChar *>(output[i])) == 0) {
+ goto continue_outer;
+ }
+ }
+
+ // The string was not found; add it to the UVector.
+ // ANDY: This requires a const_cast. Why?
+ output.addElement(const_cast<UChar *>(pattern), status);
+
+ continue_outer:
+ continue;
+ }
+}
+
+void CompactData::CompactDataSink::put(const char *key, ResourceValue &value, UBool /*noFallback*/,
+ UErrorCode &status) {
+ // traverse into the table of powers of ten
+ ResourceTable powersOfTenTable = value.getTable(status);
+ if (U_FAILURE(status)) { return; }
+ for (int i3 = 0; powersOfTenTable.getKeyAndValue(i3, key, value); ++i3) {
+
+ // Assumes that the keys are always of the form "10000" where the magnitude is the
+ // length of the key minus one. We expect magnitudes to be less than MAX_DIGITS.
+ auto magnitude = static_cast<int8_t> (strlen(key) - 1);
+ int8_t multiplier = data.multipliers[magnitude];
+ U_ASSERT(magnitude < COMPACT_MAX_DIGITS);
+
+ // Iterate over the plural variants ("one", "other", etc)
+ ResourceTable pluralVariantsTable = value.getTable(status);
+ if (U_FAILURE(status)) { return; }
+ for (int i4 = 0; pluralVariantsTable.getKeyAndValue(i4, key, value); ++i4) {
+
+ // Skip this magnitude/plural if we already have it from a child locale.
+ // Note: This also skips USE_FALLBACK entries.
+ StandardPlural::Form plural = StandardPlural::fromString(key, status);
+ if (U_FAILURE(status)) { return; }
+ if (data.patterns[getIndex(magnitude, plural)] != nullptr) {
+ continue;
+ }
+
+ // The value "0" means that we need to use the default pattern and not fall back
+ // to parent locales. Example locale where this is relevant: 'it'.
+ int32_t patternLength;
+ const UChar *patternString = value.getString(patternLength, status);
+ if (U_FAILURE(status)) { return; }
+ if (u_strcmp(patternString, u"0") == 0) {
+ patternString = USE_FALLBACK;
+ patternLength = 0;
+ }
+
+ // Save the pattern string. We will parse it lazily.
+ data.patterns[getIndex(magnitude, plural)] = patternString;
+
+ // If necessary, compute the multiplier: the difference between the magnitude
+ // and the number of zeros in the pattern.
+ if (multiplier == 0) {
+ int32_t numZeros = countZeros(patternString, patternLength);
+ if (numZeros > 0) { // numZeros==0 in certain cases, like Somali "Kun"
+ multiplier = static_cast<int8_t> (numZeros - magnitude - 1);
+ }
+ }
+ }
+
+ // Save the multiplier.
+ if (data.multipliers[magnitude] == 0) {
+ data.multipliers[magnitude] = multiplier;
+ if (magnitude > data.largestMagnitude) {
+ data.largestMagnitude = magnitude;
+ }
+ data.isEmpty = false;
+ } else {
+ U_ASSERT(data.multipliers[magnitude] == multiplier);
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////
+/// END OF CompactData.java; BEGIN CompactNotation.java ///
+///////////////////////////////////////////////////////////
+
+CompactHandler::CompactHandler(
+ CompactStyle compactStyle,
+ const Locale &locale,
+ const char *nsName,
+ CompactType compactType,
+ const PluralRules *rules,
+ MutablePatternModifier *buildReference,
+ bool safe,
+ const MicroPropsGenerator *parent,
+ UErrorCode &status)
+ : rules(rules), parent(parent), safe(safe) {
+ data.populate(locale, nsName, compactStyle, compactType, status);
+ if (safe) {
+ // Safe code path
+ precomputeAllModifiers(*buildReference, status);
+ } else {
+ // Unsafe code path
+ // Store the MutablePatternModifier reference.
+ unsafePatternModifier = buildReference;
+ }
+}
+
+CompactHandler::~CompactHandler() {
+ for (int32_t i = 0; i < precomputedModsLength; i++) {
+ delete precomputedMods[i].mod;
+ }
+}
+
+void CompactHandler::precomputeAllModifiers(MutablePatternModifier &buildReference, UErrorCode &status) {
+ if (U_FAILURE(status)) { return; }
+
+ // Initial capacity of 12 for 0K, 00K, 000K, ...M, ...B, and ...T
+ UVector allPatterns(12, status);
+ if (U_FAILURE(status)) { return; }
+ data.getUniquePatterns(allPatterns, status);
+ if (U_FAILURE(status)) { return; }
+
+ // C++ only: ensure that precomputedMods has room.
+ precomputedModsLength = allPatterns.size();
+ if (precomputedMods.getCapacity() < precomputedModsLength) {
+ precomputedMods.resize(allPatterns.size(), status);
+ if (U_FAILURE(status)) { return; }
+ }
+
+ for (int32_t i = 0; i < precomputedModsLength; i++) {
+ auto patternString = static_cast<const UChar *>(allPatterns[i]);
+ UnicodeString hello(patternString);
+ CompactModInfo &info = precomputedMods[i];
+ ParsedPatternInfo patternInfo;
+ PatternParser::parseToPatternInfo(UnicodeString(patternString), patternInfo, status);
+ if (U_FAILURE(status)) { return; }
+ buildReference.setPatternInfo(&patternInfo, {UFIELD_CATEGORY_NUMBER, UNUM_COMPACT_FIELD});
+ info.mod = buildReference.createImmutable(status);
+ if (U_FAILURE(status)) { return; }
+ info.patternString = patternString;
+ }
+}
+
+void CompactHandler::processQuantity(DecimalQuantity &quantity, MicroProps &micros,
+ UErrorCode &status) const {
+ parent->processQuantity(quantity, micros, status);
+ if (U_FAILURE(status)) { return; }
+
+ // Treat zero, NaN, and infinity as if they had magnitude 0
+ int32_t magnitude;
+ int32_t multiplier = 0;
+ if (quantity.isZeroish()) {
+ magnitude = 0;
+ micros.rounder.apply(quantity, status);
+ } else {
+ // TODO: Revisit chooseMultiplierAndApply
+ multiplier = micros.rounder.chooseMultiplierAndApply(quantity, data, status);
+ magnitude = quantity.isZeroish() ? 0 : quantity.getMagnitude();
+ magnitude -= multiplier;
+ }
+
+ StandardPlural::Form plural = utils::getStandardPlural(rules, quantity);
+ const UChar *patternString = data.getPattern(magnitude, plural);
+ if (patternString == nullptr) {
+ // Use the default (non-compact) modifier.
+ // No need to take any action.
+ } else if (safe) {
+ // Safe code path.
+ // Java uses a hash set here for O(1) lookup. C++ uses a linear search.
+ // TODO: Benchmark this and maybe change to a binary search or hash table.
+ int32_t i = 0;
+ for (; i < precomputedModsLength; i++) {
+ const CompactModInfo &info = precomputedMods[i];
+ if (u_strcmp(patternString, info.patternString) == 0) {
+ info.mod->applyToMicros(micros, quantity, status);
+ break;
+ }
+ }
+ // It should be guaranteed that we found the entry.
+ U_ASSERT(i < precomputedModsLength);
+ } else {
+ // Unsafe code path.
+ // Overwrite the PatternInfo in the existing modMiddle.
+ // C++ Note: Use unsafePatternInfo for proper lifecycle.
+ ParsedPatternInfo &patternInfo = const_cast<CompactHandler *>(this)->unsafePatternInfo;
+ PatternParser::parseToPatternInfo(UnicodeString(patternString), patternInfo, status);
+ unsafePatternModifier->setPatternInfo(
+ &unsafePatternInfo,
+ {UFIELD_CATEGORY_NUMBER, UNUM_COMPACT_FIELD});
+ unsafePatternModifier->setNumberProperties(quantity.signum(), StandardPlural::Form::COUNT);
+ micros.modMiddle = unsafePatternModifier;
+ }
+
+ // Change the exponent only after we select appropriate plural form
+ // for formatting purposes so that we preserve expected formatted
+ // string behavior.
+ quantity.adjustExponent(-1 * multiplier);
+
+ // We already performed rounding. Do not perform it again.
+ micros.rounder = RoundingImpl::passThrough();
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_compact.h b/contrib/libs/icu/i18n/number_compact.h
index 199d39f659..52fcf1fb18 100644
--- a/contrib/libs/icu/i18n/number_compact.h
+++ b/contrib/libs/icu/i18n/number_compact.h
@@ -1,97 +1,97 @@
-// © 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_COMPACT_H__
-#define __NUMBER_COMPACT_H__
-
-#include "standardplural.h"
-#include "number_types.h"
-#include "unicode/unum.h"
-#include "uvector.h"
-#include "resource.h"
-#include "number_patternmodifier.h"
-
-U_NAMESPACE_BEGIN namespace number {
-namespace impl {
-
-static const int32_t COMPACT_MAX_DIGITS = 15;
-
-class CompactData : public MultiplierProducer {
- public:
- CompactData();
-
- void populate(const Locale &locale, const char *nsName, CompactStyle compactStyle,
- CompactType compactType, UErrorCode &status);
-
- int32_t getMultiplier(int32_t magnitude) const U_OVERRIDE;
-
- const UChar *getPattern(int32_t magnitude, StandardPlural::Form plural) const;
-
- void getUniquePatterns(UVector &output, UErrorCode &status) const;
-
- private:
- const UChar *patterns[(COMPACT_MAX_DIGITS + 1) * StandardPlural::COUNT];
- int8_t multipliers[COMPACT_MAX_DIGITS + 1];
- int8_t largestMagnitude;
- UBool isEmpty;
-
- class CompactDataSink : public ResourceSink {
- public:
- explicit CompactDataSink(CompactData &data) : data(data) {}
-
- void put(const char *key, ResourceValue &value, UBool /*noFallback*/, UErrorCode &status) U_OVERRIDE;
-
- private:
- CompactData &data;
- };
-};
-
-struct CompactModInfo {
- const ImmutablePatternModifier *mod;
- const UChar* patternString;
-};
-
-class CompactHandler : public MicroPropsGenerator, public UMemory {
- public:
- CompactHandler(
- CompactStyle compactStyle,
- const Locale &locale,
- const char *nsName,
- CompactType compactType,
- const PluralRules *rules,
- MutablePatternModifier *buildReference,
- bool safe,
- const MicroPropsGenerator *parent,
- UErrorCode &status);
-
- ~CompactHandler() U_OVERRIDE;
-
- void
- processQuantity(DecimalQuantity &quantity, MicroProps &micros, UErrorCode &status) const U_OVERRIDE;
-
- private:
- const PluralRules *rules;
- const MicroPropsGenerator *parent;
- // Initial capacity of 12 for 0K, 00K, 000K, ...M, ...B, and ...T
- MaybeStackArray<CompactModInfo, 12> precomputedMods;
- int32_t precomputedModsLength = 0;
- CompactData data;
- ParsedPatternInfo unsafePatternInfo;
- MutablePatternModifier* unsafePatternModifier;
- UBool safe;
-
- /** Used by the safe code path */
- void precomputeAllModifiers(MutablePatternModifier &buildReference, UErrorCode &status);
-};
-
-
-} // namespace impl
-} // namespace number
-U_NAMESPACE_END
-
-#endif //__NUMBER_COMPACT_H__
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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_COMPACT_H__
+#define __NUMBER_COMPACT_H__
+
+#include "standardplural.h"
+#include "number_types.h"
+#include "unicode/unum.h"
+#include "uvector.h"
+#include "resource.h"
+#include "number_patternmodifier.h"
+
+U_NAMESPACE_BEGIN namespace number {
+namespace impl {
+
+static const int32_t COMPACT_MAX_DIGITS = 15;
+
+class CompactData : public MultiplierProducer {
+ public:
+ CompactData();
+
+ void populate(const Locale &locale, const char *nsName, CompactStyle compactStyle,
+ CompactType compactType, UErrorCode &status);
+
+ int32_t getMultiplier(int32_t magnitude) const U_OVERRIDE;
+
+ const UChar *getPattern(int32_t magnitude, StandardPlural::Form plural) const;
+
+ void getUniquePatterns(UVector &output, UErrorCode &status) const;
+
+ private:
+ const UChar *patterns[(COMPACT_MAX_DIGITS + 1) * StandardPlural::COUNT];
+ int8_t multipliers[COMPACT_MAX_DIGITS + 1];
+ int8_t largestMagnitude;
+ UBool isEmpty;
+
+ class CompactDataSink : public ResourceSink {
+ public:
+ explicit CompactDataSink(CompactData &data) : data(data) {}
+
+ void put(const char *key, ResourceValue &value, UBool /*noFallback*/, UErrorCode &status) U_OVERRIDE;
+
+ private:
+ CompactData &data;
+ };
+};
+
+struct CompactModInfo {
+ const ImmutablePatternModifier *mod;
+ const UChar* patternString;
+};
+
+class CompactHandler : public MicroPropsGenerator, public UMemory {
+ public:
+ CompactHandler(
+ CompactStyle compactStyle,
+ const Locale &locale,
+ const char *nsName,
+ CompactType compactType,
+ const PluralRules *rules,
+ MutablePatternModifier *buildReference,
+ bool safe,
+ const MicroPropsGenerator *parent,
+ UErrorCode &status);
+
+ ~CompactHandler() U_OVERRIDE;
+
+ void
+ processQuantity(DecimalQuantity &quantity, MicroProps &micros, UErrorCode &status) const U_OVERRIDE;
+
+ private:
+ const PluralRules *rules;
+ const MicroPropsGenerator *parent;
+ // Initial capacity of 12 for 0K, 00K, 000K, ...M, ...B, and ...T
+ MaybeStackArray<CompactModInfo, 12> precomputedMods;
+ int32_t precomputedModsLength = 0;
+ CompactData data;
+ ParsedPatternInfo unsafePatternInfo;
+ MutablePatternModifier* unsafePatternModifier;
+ UBool safe;
+
+ /** Used by the safe code path */
+ void precomputeAllModifiers(MutablePatternModifier &buildReference, UErrorCode &status);
+};
+
+
+} // namespace impl
+} // namespace number
+U_NAMESPACE_END
+
+#endif //__NUMBER_COMPACT_H__
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_currencysymbols.cpp b/contrib/libs/icu/i18n/number_currencysymbols.cpp
index 4d6fb2cb1d..2ad6cb823f 100644
--- a/contrib/libs/icu/i18n/number_currencysymbols.cpp
+++ b/contrib/libs/icu/i18n/number_currencysymbols.cpp
@@ -1,121 +1,121 @@
-// © 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();
- int32_t symbolLen = 0;
- const char16_t* symbol = ucurr_getName(
- isoCode,
- fLocaleName.data(),
- selector,
- nullptr /* isChoiceFormat */,
- &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();
- int32_t symbolLen = 0;
- const char16_t* symbol = ucurr_getPluralName(
- isoCode,
- fLocaleName.data(),
- nullptr /* 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 */
+// © 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();
+ int32_t symbolLen = 0;
+ const char16_t* symbol = ucurr_getName(
+ isoCode,
+ fLocaleName.data(),
+ selector,
+ nullptr /* isChoiceFormat */,
+ &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();
+ int32_t symbolLen = 0;
+ const char16_t* symbol = ucurr_getPluralName(
+ isoCode,
+ fLocaleName.data(),
+ nullptr /* 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/contrib/libs/icu/i18n/number_currencysymbols.h b/contrib/libs/icu/i18n/number_currencysymbols.h
index 9996bf96ae..ef4f9a3de8 100644
--- a/contrib/libs/icu/i18n/number_currencysymbols.h
+++ b/contrib/libs/icu/i18n/number_currencysymbols.h
@@ -1,65 +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 */
+// © 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/contrib/libs/icu/i18n/number_decimalquantity.cpp b/contrib/libs/icu/i18n/number_decimalquantity.cpp
index 482e93dc7a..669ec7d556 100644
--- a/contrib/libs/icu/i18n/number_decimalquantity.cpp
+++ b/contrib/libs/icu/i18n/number_decimalquantity.cpp
@@ -1,1347 +1,1347 @@
-// © 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
-
-#include <cstdlib>
-#include <cmath>
-#include <limits>
-#include <stdlib.h>
-
-#include "unicode/plurrule.h"
-#include "cmemory.h"
-#include "number_decnum.h"
-#include "putilimp.h"
-#include "number_decimalquantity.h"
-#include "number_roundingutils.h"
-#include "double-conversion.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 {
-
-int8_t NEGATIVE_FLAG = 1;
-int8_t INFINITY_FLAG = 2;
-int8_t NAN_FLAG = 4;
-
-/** 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.
- int32_t diff = static_cast<int32_t>(static_cast<uint32_t>(a) - static_cast<uint32_t>(b));
- if (b < 0 && diff < a) { return INT32_MAX; }
- if (b > 0 && diff > a) { return INT32_MIN; }
- return diff;
-}
-
-static double DOUBLE_MULTIPLIERS[] = {
- 1e0,
- 1e1,
- 1e2,
- 1e3,
- 1e4,
- 1e5,
- 1e6,
- 1e7,
- 1e8,
- 1e9,
- 1e10,
- 1e11,
- 1e12,
- 1e13,
- 1e14,
- 1e15,
- 1e16,
- 1e17,
- 1e18,
- 1e19,
- 1e20,
- 1e21};
-
-} // namespace
-
-icu::IFixedDecimal::~IFixedDecimal() = default;
-
-DecimalQuantity::DecimalQuantity() {
- setBcdToZero();
- flags = 0;
-}
-
-DecimalQuantity::~DecimalQuantity() {
- if (usingBytes) {
- uprv_free(fBCD.bcdBytes.ptr);
- fBCD.bcdBytes.ptr = nullptr;
- usingBytes = false;
- }
-}
-
-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;
- lReqPos = other.lReqPos;
- rReqPos = other.rReqPos;
- scale = other.scale;
- precision = other.precision;
- flags = other.flags;
- origDouble = other.origDouble;
- origDelta = other.origDelta;
- isApproximate = other.isApproximate;
- exponent = other.exponent;
-}
-
-void DecimalQuantity::clear() {
- lReqPos = 0;
- rReqPos = 0;
- flags = 0;
- setBcdToZero(); // sets scale, precision, hasDouble, origDouble, origDelta, and BCD data
-}
-
-void DecimalQuantity::setMinInteger(int32_t minInt) {
- // Validation should happen outside of DecimalQuantity, e.g., in the Precision class.
- U_ASSERT(minInt >= 0);
-
- // 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
- lReqPos = minInt;
-}
-
-void DecimalQuantity::setMinFraction(int32_t minFrac) {
- // Validation should happen outside of DecimalQuantity, e.g., in the Precision class.
- U_ASSERT(minFrac >= 0);
-
- // Save values into internal state
- // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE
- rReqPos = -minFrac;
-}
-
-void DecimalQuantity::applyMaxInteger(int32_t maxInt) {
- // Validation should happen outside of DecimalQuantity, e.g., in the Precision class.
- U_ASSERT(maxInt >= 0);
-
- if (precision == 0) {
- return;
- }
-
- if (maxInt <= scale) {
- setBcdToZero();
- return;
- }
-
- int32_t magnitude = getMagnitude();
- if (maxInt <= magnitude) {
- popFromLeft(magnitude - maxInt + 1);
- compact();
- }
-}
-
-uint64_t DecimalQuantity::getPositionFingerprint() const {
- uint64_t fingerprint = 0;
- fingerprint ^= (lReqPos << 16);
- fingerprint ^= (static_cast<uint64_t>(rReqPos) << 32);
- return fingerprint;
-}
-
-void DecimalQuantity::roundToIncrement(double roundingIncrement, RoundingMode roundingMode,
- UErrorCode& status) {
- // Do not call this method with an increment having only a 1 or a 5 digit!
- // Use a more efficient call to either roundToMagnitude() or roundToNickel().
- // Check a few popular rounding increments; a more thorough check is in Java.
- U_ASSERT(roundingIncrement != 0.01);
- U_ASSERT(roundingIncrement != 0.05);
- U_ASSERT(roundingIncrement != 0.1);
- U_ASSERT(roundingIncrement != 0.5);
- U_ASSERT(roundingIncrement != 1);
- U_ASSERT(roundingIncrement != 5);
-
- DecNum incrementDN;
- incrementDN.setTo(roundingIncrement, status);
- if (U_FAILURE(status)) { return; }
-
- // Divide this DecimalQuantity by the increment, round, then multiply back.
- divideBy(incrementDN, status);
- if (U_FAILURE(status)) { return; }
- roundToMagnitude(0, roundingMode, status);
- if (U_FAILURE(status)) { return; }
- multiplyBy(incrementDN, status);
- if (U_FAILURE(status)) { return; }
-}
-
-void DecimalQuantity::multiplyBy(const DecNum& multiplicand, UErrorCode& status) {
- if (isZeroish()) {
- return;
- }
- // 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 (isZeroish()) {
- 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 {
- U_ASSERT(precision != 0);
- return scale + precision - 1;
-}
-
-bool DecimalQuantity::adjustMagnitude(int32_t delta) {
- if (precision != 0) {
- // 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 {
- // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
- // See the comment at the top of this file explaining the "isApproximate" field.
- U_ASSERT(!isApproximate);
-
- switch (operand) {
- case PLURAL_OPERAND_I:
- // Invert the negative sign if necessary
- return static_cast<double>(isNegative() ? -toLong(true) : toLong(true));
- case PLURAL_OPERAND_F:
- return static_cast<double>(toFractionLong(true));
- case PLURAL_OPERAND_T:
- return static_cast<double>(toFractionLong(false));
- case PLURAL_OPERAND_V:
- return fractionCount();
- case PLURAL_OPERAND_W:
- return fractionCountWithoutTrailingZeros();
- case PLURAL_OPERAND_E:
- return static_cast<double>(getExponent());
- default:
- return std::abs(toDouble());
- }
-}
-
-int32_t DecimalQuantity::getExponent() const {
- return exponent;
-}
-
-void DecimalQuantity::adjustExponent(int delta) {
- exponent = exponent + delta;
-}
-
-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.
- U_ASSERT(!isApproximate);
-
- int32_t magnitude = scale + precision;
- int32_t result = (lReqPos > magnitude) ? lReqPos : magnitude;
- return result - 1;
-}
-
-int32_t DecimalQuantity::getLowerDisplayMagnitude() 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);
-
- int32_t magnitude = scale;
- int32_t result = (rReqPos < magnitude) ? rReqPos : magnitude;
- return result;
-}
-
-int8_t DecimalQuantity::getDigit(int32_t magnitude) const {
- // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
- // See the comment at the top of this file explaining the "isApproximate" field.
- U_ASSERT(!isApproximate);
-
- return getDigitPos(magnitude - scale);
-}
-
-int32_t DecimalQuantity::fractionCount() const {
- int32_t fractionCountWithExponent = -getLowerDisplayMagnitude() - exponent;
- return fractionCountWithExponent > 0 ? fractionCountWithExponent : 0;
-}
-
-int32_t DecimalQuantity::fractionCountWithoutTrailingZeros() const {
- int32_t fractionCountWithExponent = -scale - exponent;
- return fractionCountWithExponent > 0 ? fractionCountWithExponent : 0; // max(-fractionCountWithExponent, 0)
-}
-
-bool DecimalQuantity::isNegative() const {
- return (flags & NEGATIVE_FLAG) != 0;
-}
-
-Signum DecimalQuantity::signum() const {
- bool isZero = (isZeroish() && !isInfinite());
- bool isNeg = isNegative();
- if (isZero && isNeg) {
- return SIGNUM_NEG_ZERO;
- } else if (isZero) {
- return SIGNUM_POS_ZERO;
- } else if (isNeg) {
- return SIGNUM_NEG;
- } else {
- return SIGNUM_POS;
- }
-}
-
-bool DecimalQuantity::isInfinite() const {
- return (flags & INFINITY_FLAG) != 0;
-}
-
-bool DecimalQuantity::isNaN() const {
- return (flags & NAN_FLAG) != 0;
-}
-
-bool DecimalQuantity::isZeroish() const {
- return precision == 0;
-}
-
-DecimalQuantity &DecimalQuantity::setToInt(int32_t n) {
- setBcdToZero();
- flags = 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;
- }
- if (n != 0) {
- _setToInt(n);
- compact();
- }
- return *this;
-}
-
-void DecimalQuantity::_setToInt(int32_t n) {
- if (n == INT32_MIN) {
- readLongToBcd(-static_cast<int64_t>(n));
- } else {
- readIntToBcd(n);
- }
-}
-
-DecimalQuantity &DecimalQuantity::setToLong(int64_t n) {
- setBcdToZero();
- flags = 0;
- if (n < 0 && n > INT64_MIN) {
- flags |= NEGATIVE_FLAG;
- n = -n;
- }
- if (n != 0) {
- _setToLong(n);
- compact();
- }
- return *this;
-}
-
-void DecimalQuantity::_setToLong(int64_t n) {
- if (n == INT64_MIN) {
- 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<int32_t>(n));
- } else {
- readLongToBcd(n);
- }
-}
-
-DecimalQuantity &DecimalQuantity::setToDouble(double n) {
- setBcdToZero();
- flags = 0;
- // signbit() from <math.h> handles +0.0 vs -0.0
- if (std::signbit(n)) {
- flags |= NEGATIVE_FLAG;
- n = -n;
- }
- if (std::isnan(n) != 0) {
- flags |= NAN_FLAG;
- } else if (std::isfinite(n) == 0) {
- flags |= INFINITY_FLAG;
- } else if (n != 0) {
- _setToDoubleFast(n);
- compact();
- }
- return *this;
-}
-
-void DecimalQuantity::_setToDoubleFast(double n) {
- isApproximate = true;
- origDouble = n;
- origDelta = 0;
-
- // Make sure the double is an IEEE 754 double. If not, fall back to the slow path right now.
- // TODO: Make a fast path for other types of doubles.
- if (!std::numeric_limits<double>::is_iec559) {
- convertToAccurateDouble();
- return;
- }
-
- // To get the bits from the double, use memcpy, which takes care of endianness.
- uint64_t ieeeBits;
- uprv_memcpy(&ieeeBits, &n, sizeof(n));
- int32_t exponent = static_cast<int32_t>((ieeeBits & 0x7ff0000000000000L) >> 52) - 0x3ff;
-
- // Not all integers can be represented exactly for exponent > 52
- if (exponent <= 52 && static_cast<int64_t>(n) == n) {
- _setToLong(static_cast<int64_t>(n));
- return;
- }
-
- if (exponent == -1023 || exponent == 1024) {
- // The extreme values of exponent are special; use slow path.
- convertToAccurateDouble();
- return;
- }
-
- // 3.3219... is log2(10)
- auto fracLength = static_cast<int32_t> ((52 - exponent) / 3.32192809488736234787031942948939017586);
- if (fracLength >= 0) {
- int32_t i = fracLength;
- // 1e22 is the largest exact double.
- for (; i >= 22; i -= 22) n *= 1e22;
- n *= DOUBLE_MULTIPLIERS[i];
- } else {
- int32_t i = fracLength;
- // 1e22 is the largest exact double.
- for (; i <= -22; i += 22) n /= 1e22;
- n /= DOUBLE_MULTIPLIERS[-i];
- }
- auto result = static_cast<int64_t>(uprv_round(n));
- if (result != 0) {
- _setToLong(result);
- scale -= fracLength;
- }
-}
-
-void DecimalQuantity::convertToAccurateDouble() {
- U_ASSERT(origDouble != 0);
- int32_t delta = origDelta;
-
- // Call the slow oracle function (Double.toString in Java, DoubleToAscii in C++).
- char buffer[DoubleToStringConverter::kBase10MaximalLength + 1];
- bool sign; // unused; always positive
- int32_t length;
- int32_t point;
- DoubleToStringConverter::DoubleToAscii(
- origDouble,
- DoubleToStringConverter::DtoaMode::SHORTEST,
- 0,
- buffer,
- sizeof(buffer),
- &sign,
- &length,
- &point
- );
-
- setBcdToZero();
- readDoubleConversionToBcd(buffer, length, point);
- scale += delta;
- explicitExactDouble = true;
-}
-
-DecimalQuantity &DecimalQuantity::setToDecNumber(StringPiece n, UErrorCode& status) {
- setBcdToZero();
- flags = 0;
-
- // Compute the decNumber representation
- DecNum decnum;
- decnum.setTo(n, status);
-
- _setToDecNum(decnum, status);
- return *this;
-}
-
-DecimalQuantity& DecimalQuantity::setToDecNum(const DecNum& decnum, UErrorCode& status) {
- setBcdToZero();
- flags = 0;
-
- _setToDecNum(decnum, status);
- return *this;
-}
-
-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 = exponent + scale + precision - 1;
- if (truncateIfOverflow) {
- upperMagnitude = std::min(upperMagnitude, 17);
- }
- for (int32_t magnitude = upperMagnitude; magnitude >= 0; magnitude--) {
- result = result * 10 + getDigitPos(magnitude - scale - exponent);
- }
- if (isNegative()) {
- return static_cast<int64_t>(0LL - result); // i.e., -result
- }
- return static_cast<int64_t>(result);
-}
-
-uint64_t DecimalQuantity::toFractionLong(bool includeTrailingZeros) const {
- uint64_t result = 0L;
- int32_t magnitude = -1 - exponent;
- int32_t lowerMagnitude = scale;
- 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;
-}
-
-bool DecimalQuantity::fitsInLong(bool ignoreFraction) const {
- if (isInfinite() || isNaN()) {
- return false;
- }
- if (isZeroish()) {
- return true;
- }
- if (exponent + 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;
- } else if (isInfinite()) {
- return isNegative() ? -INFINITY : INFINITY;
- }
-
- // 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<const uint16_t*>(numberString.getBuffer()),
- numberString.length(),
- &count);
-}
-
-void DecimalQuantity::toDecNum(DecNum& output, UErrorCode& status) const {
- // Special handling for zero
- if (precision == 0) {
- output.setTo("0", status);
- }
-
- // 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<uint8_t, 20> ubcd(precision);
- for (int32_t m = 0; m < precision; m++) {
- ubcd[precision - m - 1] = static_cast<uint8_t>(getDigitPos(m));
- }
- output.setTo(ubcd.getAlias(), precision, scale, isNegative(), status);
-}
-
-void DecimalQuantity::truncate() {
- if (scale < 0) {
- shiftRight(-scale);
- scale = 0;
- compact();
- }
-}
-
-void DecimalQuantity::roundToNickel(int32_t magnitude, RoundingMode roundingMode, UErrorCode& status) {
- roundToMagnitude(magnitude, roundingMode, true, status);
-}
-
-void DecimalQuantity::roundToMagnitude(int32_t magnitude, RoundingMode roundingMode, UErrorCode& status) {
- roundToMagnitude(magnitude, roundingMode, false, status);
-}
-
-void DecimalQuantity::roundToMagnitude(int32_t magnitude, RoundingMode roundingMode, bool nickel, UErrorCode& status) {
- // The position in the BCD at which rounding will be performed; digits to the right of position
- // will be rounded away.
- int position = safeSubtract(magnitude, scale);
-
- // "trailing" = least significant digit to the left of rounding
- int8_t trailingDigit = getDigitPos(position);
-
- if (position <= 0 && !isApproximate && (!nickel || trailingDigit == 0 || trailingDigit == 5)) {
- // All digits are to the left of the rounding magnitude.
- } else if (precision == 0) {
- // No rounding for zero.
- } else {
- // Perform rounding logic.
- // "leading" = most significant digit to the right of rounding
- int8_t leadingDigit = getDigitPos(safeSubtract(position, 1));
-
- // Compute which section of the number we are in.
- // EDGE means we are at the bottom or top edge, like 1.000 or 1.999 (used by doubles)
- // LOWER means we are between the bottom edge and the midpoint, like 1.391
- // MIDPOINT means we are exactly in the middle, like 1.500
- // UPPER means we are between the midpoint and the top edge, like 1.916
- roundingutils::Section section;
- if (!isApproximate) {
- if (nickel && trailingDigit != 2 && trailingDigit != 7) {
- // Nickel rounding, and not at .02x or .07x
- if (trailingDigit < 2) {
- // .00, .01 => down to .00
- section = roundingutils::SECTION_LOWER;
- } else if (trailingDigit < 5) {
- // .03, .04 => up to .05
- section = roundingutils::SECTION_UPPER;
- } else if (trailingDigit < 7) {
- // .05, .06 => down to .05
- section = roundingutils::SECTION_LOWER;
- } else {
- // .08, .09 => up to .10
- section = roundingutils::SECTION_UPPER;
- }
- } else if (leadingDigit < 5) {
- // Includes nickel rounding .020-.024 and .070-.074
- section = roundingutils::SECTION_LOWER;
- } else if (leadingDigit > 5) {
- // Includes nickel rounding .026-.029 and .076-.079
- section = roundingutils::SECTION_UPPER;
- } else {
- // Includes nickel rounding .025 and .075
- section = roundingutils::SECTION_MIDPOINT;
- for (int p = safeSubtract(position, 2); p >= 0; p--) {
- if (getDigitPos(p) != 0) {
- section = roundingutils::SECTION_UPPER;
- break;
- }
- }
- }
- } else {
- int32_t p = safeSubtract(position, 2);
- int32_t minP = uprv_max(0, precision - 14);
- if (leadingDigit == 0 && (!nickel || trailingDigit == 0 || trailingDigit == 5)) {
- section = roundingutils::SECTION_LOWER_EDGE;
- for (; p >= minP; p--) {
- if (getDigitPos(p) != 0) {
- section = roundingutils::SECTION_LOWER;
- break;
- }
- }
- } else if (leadingDigit == 4 && (!nickel || trailingDigit == 2 || trailingDigit == 7)) {
- section = roundingutils::SECTION_MIDPOINT;
- for (; p >= minP; p--) {
- if (getDigitPos(p) != 9) {
- section = roundingutils::SECTION_LOWER;
- break;
- }
- }
- } else if (leadingDigit == 5 && (!nickel || trailingDigit == 2 || trailingDigit == 7)) {
- section = roundingutils::SECTION_MIDPOINT;
- for (; p >= minP; p--) {
- if (getDigitPos(p) != 0) {
- section = roundingutils::SECTION_UPPER;
- break;
- }
- }
- } else if (leadingDigit == 9 && (!nickel || trailingDigit == 4 || trailingDigit == 9)) {
- section = roundingutils::SECTION_UPPER_EDGE;
- for (; p >= minP; p--) {
- if (getDigitPos(p) != 9) {
- section = roundingutils::SECTION_UPPER;
- break;
- }
- }
- } else if (nickel && trailingDigit != 2 && trailingDigit != 7) {
- // Nickel rounding, and not at .02x or .07x
- if (trailingDigit < 2) {
- // .00, .01 => down to .00
- section = roundingutils::SECTION_LOWER;
- } else if (trailingDigit < 5) {
- // .03, .04 => up to .05
- section = roundingutils::SECTION_UPPER;
- } else if (trailingDigit < 7) {
- // .05, .06 => down to .05
- section = roundingutils::SECTION_LOWER;
- } else {
- // .08, .09 => up to .10
- section = roundingutils::SECTION_UPPER;
- }
- } else if (leadingDigit < 5) {
- // Includes nickel rounding .020-.024 and .070-.074
- section = roundingutils::SECTION_LOWER;
- } else {
- // Includes nickel rounding .026-.029 and .076-.079
- section = roundingutils::SECTION_UPPER;
- }
-
- bool roundsAtMidpoint = roundingutils::roundsAtMidpoint(roundingMode);
- if (safeSubtract(position, 1) < precision - 14 ||
- (roundsAtMidpoint && section == roundingutils::SECTION_MIDPOINT) ||
- (!roundsAtMidpoint && section < 0 /* i.e. at upper or lower edge */)) {
- // Oops! This means that we have to get the exact representation of the double,
- // because the zone of uncertainty is along the rounding boundary.
- convertToAccurateDouble();
- roundToMagnitude(magnitude, roundingMode, nickel, status); // start over
- return;
- }
-
- // Turn off the approximate double flag, since the value is now confirmed to be exact.
- isApproximate = false;
- origDouble = 0.0;
- origDelta = 0;
-
- if (position <= 0 && (!nickel || trailingDigit == 0 || trailingDigit == 5)) {
- // All digits are to the left of the rounding magnitude.
- return;
- }
-
- // Good to continue rounding.
- if (section == -1) { section = roundingutils::SECTION_LOWER; }
- if (section == -2) { section = roundingutils::SECTION_UPPER; }
- }
-
- // Nickel rounding "half even" goes to the nearest whole (away from the 5).
- bool isEven = nickel
- ? (trailingDigit < 2 || trailingDigit > 7
- || (trailingDigit == 2 && section != roundingutils::SECTION_UPPER)
- || (trailingDigit == 7 && section == roundingutils::SECTION_UPPER))
- : (trailingDigit % 2) == 0;
-
- bool roundDown = roundingutils::getRoundingDirection(isEven,
- isNegative(),
- section,
- roundingMode,
- status);
- if (U_FAILURE(status)) {
- return;
- }
-
- // Perform truncation
- if (position >= precision) {
- setBcdToZero();
- scale = magnitude;
- } else {
- shiftRight(position);
- }
-
- if (nickel) {
- if (trailingDigit < 5 && roundDown) {
- setDigitPos(0, 0);
- compact();
- return;
- } else if (trailingDigit >= 5 && !roundDown) {
- setDigitPos(0, 9);
- trailingDigit = 9;
- // do not return: use the bubbling logic below
- } else {
- setDigitPos(0, 5);
- // compact not necessary: digit at position 0 is nonzero
- return;
- }
- }
-
- // Bubble the result to the higher digits
- if (!roundDown) {
- if (trailingDigit == 9) {
- int bubblePos = 0;
- // Note: in the long implementation, the most digits BCD can have at this point is
- // 15, so bubblePos <= 15 and getDigitPos(bubblePos) is safe.
- for (; getDigitPos(bubblePos) == 9; bubblePos++) {}
- shiftRight(bubblePos); // shift off the trailing 9s
- }
- int8_t digit0 = getDigitPos(0);
- U_ASSERT(digit0 != 9);
- setDigitPos(0, static_cast<int8_t>(digit0 + 1));
- precision += 1; // in case an extra digit got added
- }
-
- compact();
- }
-}
-
-void DecimalQuantity::roundToInfinity() {
- if (isApproximate) {
- convertToAccurateDouble();
- }
-}
-
-void DecimalQuantity::appendDigit(int8_t value, int32_t leadingZeros, bool appendAsInteger) {
- U_ASSERT(leadingZeros >= 0);
-
- // Zero requires special handling to maintain the invariant that the least-significant digit
- // in the BCD is nonzero.
- if (value == 0) {
- if (appendAsInteger && precision != 0) {
- scale += leadingZeros + 1;
- }
- return;
- }
-
- // Deal with trailing zeros
- if (scale > 0) {
- leadingZeros += scale;
- if (appendAsInteger) {
- scale = 0;
- }
- }
-
- // Append digit
- shiftLeft(leadingZeros + 1);
- setDigitPos(0, value);
-
- // Fix scale if in integer mode
- if (appendAsInteger) {
- scale += leadingZeros + 1;
- }
-}
-
-UnicodeString DecimalQuantity::toPlainString() const {
- U_ASSERT(!isApproximate);
- UnicodeString sb;
- if (isNegative()) {
- sb.append(u'-');
- }
- if (precision == 0) {
- sb.append(u'0');
- return sb;
- }
- int32_t upper = scale + precision + exponent - 1;
- int32_t lower = scale + exponent;
- if (upper < lReqPos - 1) {
- upper = lReqPos - 1;
- }
- if (lower > rReqPos) {
- lower = rReqPos;
- }
- int32_t p = upper;
- if (p < 0) {
- sb.append(u'0');
- }
- for (; p >= 0; p--) {
- sb.append(u'0' + getDigitPos(p - scale - exponent));
- }
- if (lower < 0) {
- sb.append(u'.');
- }
- for(; p >= lower; p--) {
- sb.append(u'0' + getDigitPos(p - scale - exponent));
- }
- 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;
- }
- int32_t upperPos = precision - 1;
- int32_t lowerPos = 0;
- 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 + exponent;
- if (_scale == INT32_MIN) {
- result.append({u"-2147483648", -1});
- return result;
- } else 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 ///
-////////////////////////////////////////////////////
-
-int8_t DecimalQuantity::getDigitPos(int32_t position) const {
- if (usingBytes) {
- if (position < 0 || position >= precision) { return 0; }
- return fBCD.bcdBytes.ptr[position];
- } else {
- if (position < 0 || position >= 16) { return 0; }
- return (int8_t) ((fBCD.bcdLong >> (position * 4)) & 0xf);
- }
-}
-
-void DecimalQuantity::setDigitPos(int32_t position, int8_t value) {
- U_ASSERT(position >= 0);
- if (usingBytes) {
- ensureCapacity(position + 1);
- fBCD.bcdBytes.ptr[position] = value;
- } else if (position >= 16) {
- switchStorage();
- ensureCapacity(position + 1);
- fBCD.bcdBytes.ptr[position] = value;
- } else {
- int shift = position * 4;
- fBCD.bcdLong = (fBCD.bcdLong & ~(0xfL << shift)) | ((long) value << shift);
- }
-}
-
-void DecimalQuantity::shiftLeft(int32_t numDigits) {
- if (!usingBytes && precision + numDigits > 16) {
- switchStorage();
- }
- if (usingBytes) {
- ensureCapacity(precision + numDigits);
- int i = precision + numDigits - 1;
- for (; i >= numDigits; i--) {
- fBCD.bcdBytes.ptr[i] = fBCD.bcdBytes.ptr[i - numDigits];
- }
- for (; i >= 0; i--) {
- fBCD.bcdBytes.ptr[i] = 0;
- }
- } else {
- fBCD.bcdLong <<= (numDigits * 4);
- }
- scale -= numDigits;
- precision += numDigits;
-}
-
-void DecimalQuantity::shiftRight(int32_t numDigits) {
- if (usingBytes) {
- int i = 0;
- for (; i < precision - numDigits; i++) {
- fBCD.bcdBytes.ptr[i] = fBCD.bcdBytes.ptr[i + numDigits];
- }
- for (; i < precision; i++) {
- fBCD.bcdBytes.ptr[i] = 0;
- }
- } else {
- fBCD.bcdLong >>= (numDigits * 4);
- }
- scale += numDigits;
- precision -= numDigits;
-}
-
-void DecimalQuantity::popFromLeft(int32_t numDigits) {
- U_ASSERT(numDigits <= precision);
- if (usingBytes) {
- int i = precision - 1;
- for (; i >= precision - numDigits; i--) {
- fBCD.bcdBytes.ptr[i] = 0;
- }
- } else {
- fBCD.bcdLong &= (static_cast<uint64_t>(1) << ((precision - numDigits) * 4)) - 1;
- }
- precision -= numDigits;
-}
-
-void DecimalQuantity::setBcdToZero() {
- if (usingBytes) {
- uprv_free(fBCD.bcdBytes.ptr);
- fBCD.bcdBytes.ptr = nullptr;
- usingBytes = false;
- }
- fBCD.bcdLong = 0L;
- scale = 0;
- precision = 0;
- isApproximate = false;
- origDouble = 0;
- origDelta = 0;
- exponent = 0;
-}
-
-void DecimalQuantity::readIntToBcd(int32_t n) {
- U_ASSERT(n != 0);
- // ints always fit inside the long implementation.
- uint64_t result = 0L;
- int i = 16;
- for (; n != 0; n /= 10, i--) {
- result = (result >> 4) + ((static_cast<uint64_t>(n) % 10) << 60);
- }
- U_ASSERT(!usingBytes);
- fBCD.bcdLong = result >> (i * 4);
- scale = 0;
- precision = 16 - i;
-}
-
-void DecimalQuantity::readLongToBcd(int64_t n) {
- U_ASSERT(n != 0);
- if (n >= 10000000000000000L) {
- ensureCapacity();
- int i = 0;
- for (; n != 0L; n /= 10L, i++) {
- fBCD.bcdBytes.ptr[i] = static_cast<int8_t>(n % 10);
- }
- U_ASSERT(usingBytes);
- scale = 0;
- precision = i;
- } else {
- uint64_t result = 0L;
- int i = 16;
- for (; n != 0L; n /= 10L, i--) {
- result = (result >> 4) + ((n % 10) << 60);
- }
- U_ASSERT(i >= 0);
- U_ASSERT(!usingBytes);
- fBCD.bcdLong = result >> (i * 4);
- scale = 0;
- precision = 16 - i;
- }
-}
-
-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++) {
- fBCD.bcdBytes.ptr[i] = dn->lsu[i];
- }
- } else {
- uint64_t result = 0L;
- for (int32_t i = 0; i < dn->digits; i++) {
- result |= static_cast<uint64_t>(dn->lsu[i]) << (4 * i);
- }
- fBCD.bcdLong = result;
- }
- scale = dn->exponent;
- precision = dn->digits;
-}
-
-void DecimalQuantity::readDoubleConversionToBcd(
- const char* buffer, int32_t length, int32_t point) {
- // NOTE: Despite the fact that double-conversion's API is called
- // "DoubleToAscii", they actually use '0' (as opposed to u8'0').
- if (length > 16) {
- ensureCapacity(length);
- for (int32_t i = 0; i < length; i++) {
- fBCD.bcdBytes.ptr[i] = buffer[length-i-1] - '0';
- }
- } else {
- uint64_t result = 0L;
- for (int32_t i = 0; i < length; i++) {
- result |= static_cast<uint64_t>(buffer[length-i-1] - '0') << (4 * i);
- }
- fBCD.bcdLong = result;
- }
- scale = point - length;
- precision = length;
-}
-
-void DecimalQuantity::compact() {
- if (usingBytes) {
- int32_t delta = 0;
- for (; delta < precision && fBCD.bcdBytes.ptr[delta] == 0; delta++);
- if (delta == precision) {
- // Number is zero
- setBcdToZero();
- return;
- } else {
- // Remove trailing zeros
- shiftRight(delta);
- }
-
- // Compute precision
- int32_t leading = precision - 1;
- for (; leading >= 0 && fBCD.bcdBytes.ptr[leading] == 0; leading--);
- precision = leading + 1;
-
- // Switch storage mechanism if possible
- if (precision <= 16) {
- switchStorage();
- }
-
- } else {
- if (fBCD.bcdLong == 0L) {
- // Number is zero
- setBcdToZero();
- return;
- }
-
- // Compact the number (remove trailing zeros)
- // TODO: Use a more efficient algorithm here and below. There is a logarithmic one.
- int32_t delta = 0;
- for (; delta < precision && getDigitPos(delta) == 0; delta++);
- fBCD.bcdLong >>= delta * 4;
- scale += delta;
-
- // Compute precision
- int32_t leading = precision - 1;
- for (; leading >= 0 && getDigitPos(leading) == 0; leading--);
- precision = leading + 1;
- }
-}
-
-void DecimalQuantity::ensureCapacity() {
- ensureCapacity(40);
-}
-
-void DecimalQuantity::ensureCapacity(int32_t capacity) {
- if (capacity == 0) { return; }
- int32_t oldCapacity = usingBytes ? fBCD.bcdBytes.len : 0;
- if (!usingBytes) {
- // TODO: There is nothing being done to check for memory allocation failures.
- // TODO: Consider indexing by nybbles instead of bytes in C++, so that we can
- // make these arrays half the size.
- fBCD.bcdBytes.ptr = static_cast<int8_t*>(uprv_malloc(capacity * sizeof(int8_t)));
- fBCD.bcdBytes.len = capacity;
- // Initialize the byte array to zeros (this is done automatically in Java)
- uprv_memset(fBCD.bcdBytes.ptr, 0, capacity * sizeof(int8_t));
- } else if (oldCapacity < capacity) {
- auto bcd1 = static_cast<int8_t*>(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(bcd1 + oldCapacity, 0, (capacity - oldCapacity) * sizeof(int8_t));
- uprv_free(fBCD.bcdBytes.ptr);
- fBCD.bcdBytes.ptr = bcd1;
- fBCD.bcdBytes.len = capacity * 2;
- }
- usingBytes = true;
-}
-
-void DecimalQuantity::switchStorage() {
- if (usingBytes) {
- // Change from bytes to long
- uint64_t bcdLong = 0L;
- for (int i = precision - 1; i >= 0; i--) {
- bcdLong <<= 4;
- bcdLong |= fBCD.bcdBytes.ptr[i];
- }
- uprv_free(fBCD.bcdBytes.ptr);
- fBCD.bcdBytes.ptr = nullptr;
- fBCD.bcdLong = bcdLong;
- usingBytes = false;
- } else {
- // Change from long to bytes
- // Copy the long into a local variable since it will get munged when we allocate the bytes
- uint64_t bcdLong = fBCD.bcdLong;
- ensureCapacity();
- for (int i = 0; i < precision; i++) {
- fBCD.bcdBytes.ptr[i] = static_cast<int8_t>(bcdLong & 0xf);
- bcdLong >>= 4;
- }
- U_ASSERT(usingBytes);
- }
-}
-
-void DecimalQuantity::copyBcdFrom(const DecimalQuantity &other) {
- setBcdToZero();
- if (other.usingBytes) {
- ensureCapacity(other.precision);
- uprv_memcpy(fBCD.bcdBytes.ptr, other.fBCD.bcdBytes.ptr, other.precision * sizeof(int8_t));
- } else {
- fBCD.bcdLong = other.fBCD.bcdLong;
- }
-}
-
-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"; }
- int32_t capacity = fBCD.bcdBytes.len;
- if (precision > capacity) { return u"Precision exceeds length of byte array"; }
- if (getDigitPos(precision - 1) == 0) { return u"Most significant digit is zero in byte mode"; }
- if (getDigitPos(0) == 0) { return u"Least significant digit is zero in long mode"; }
- for (int i = 0; i < precision; i++) {
- if (getDigitPos(i) >= 10) { return u"Digit exceeding 10 in byte array"; }
- if (getDigitPos(i) < 0) { return u"Digit below 0 in byte array"; }
- }
- for (int i = precision; i < capacity; i++) {
- if (getDigitPos(i) != 0) { return u"Nonzero digits outside of range in byte array"; }
- }
- } else {
- if (precision == 0 && fBCD.bcdLong != 0) {
- return u"Value in bcdLong even though precision is zero";
- }
- if (precision > 16) { return u"Precision exceeds length of long"; }
- if (precision != 0 && getDigitPos(precision - 1) == 0) {
- return u"Most significant digit is zero in long mode";
- }
- if (precision != 0 && getDigitPos(0) == 0) {
- return u"Least significant digit is zero in long mode";
- }
- for (int i = 0; i < precision; i++) {
- if (getDigitPos(i) >= 10) { return u"Digit exceeding 10 in long"; }
- if (getDigitPos(i) < 0) { return u"Digit below 0 in long (?!)"; }
- }
- for (int i = precision; i < 16; i++) {
- if (getDigitPos(i) != 0) { return u"Nonzero digits outside of range in long"; }
- }
- }
-
- // No error
- return nullptr;
-}
-
-bool DecimalQuantity::operator==(const DecimalQuantity& other) const {
- bool basicEquals =
- scale == other.scale
- && precision == other.precision
- && flags == other.flags
- && lReqPos == other.lReqPos
- && rReqPos == other.rReqPos
- && isApproximate == other.isApproximate;
- if (!basicEquals) {
- return false;
- }
-
- if (precision == 0) {
- return true;
- } else if (isApproximate) {
- return origDouble == other.origDouble && origDelta == other.origDelta;
- } else {
- for (int m = getUpperDisplayMagnitude(); m >= getLowerDisplayMagnitude(); m--) {
- if (getDigit(m) != other.getDigit(m)) {
- return false;
- }
- }
- return true;
- }
-}
-
-UnicodeString DecimalQuantity::toString() const {
- MaybeStackArray<char, 30> digits(precision + 1);
- for (int32_t i = 0; i < precision; i++) {
- digits[i] = getDigitPos(precision - i - 1) + '0';
- }
- digits[precision] = 0; // terminate buffer
- char buffer8[100];
- snprintf(
- buffer8,
- sizeof(buffer8),
- "<DecimalQuantity %d:%d %s %s%s%s%d>",
- lReqPos,
- rReqPos,
- (usingBytes ? "bytes" : "long"),
- (isNegative() ? "-" : ""),
- (precision == 0 ? "0" : digits.getAlias()),
- "E",
- scale);
- return UnicodeString(buffer8, -1, US_INV);
-}
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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
+
+#include <cstdlib>
+#include <cmath>
+#include <limits>
+#include <stdlib.h>
+
+#include "unicode/plurrule.h"
+#include "cmemory.h"
+#include "number_decnum.h"
+#include "putilimp.h"
+#include "number_decimalquantity.h"
+#include "number_roundingutils.h"
+#include "double-conversion.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 {
+
+int8_t NEGATIVE_FLAG = 1;
+int8_t INFINITY_FLAG = 2;
+int8_t NAN_FLAG = 4;
+
+/** 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.
+ int32_t diff = static_cast<int32_t>(static_cast<uint32_t>(a) - static_cast<uint32_t>(b));
+ if (b < 0 && diff < a) { return INT32_MAX; }
+ if (b > 0 && diff > a) { return INT32_MIN; }
+ return diff;
+}
+
+static double DOUBLE_MULTIPLIERS[] = {
+ 1e0,
+ 1e1,
+ 1e2,
+ 1e3,
+ 1e4,
+ 1e5,
+ 1e6,
+ 1e7,
+ 1e8,
+ 1e9,
+ 1e10,
+ 1e11,
+ 1e12,
+ 1e13,
+ 1e14,
+ 1e15,
+ 1e16,
+ 1e17,
+ 1e18,
+ 1e19,
+ 1e20,
+ 1e21};
+
+} // namespace
+
+icu::IFixedDecimal::~IFixedDecimal() = default;
+
+DecimalQuantity::DecimalQuantity() {
+ setBcdToZero();
+ flags = 0;
+}
+
+DecimalQuantity::~DecimalQuantity() {
+ if (usingBytes) {
+ uprv_free(fBCD.bcdBytes.ptr);
+ fBCD.bcdBytes.ptr = nullptr;
+ usingBytes = false;
+ }
+}
+
+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;
+ lReqPos = other.lReqPos;
+ rReqPos = other.rReqPos;
+ scale = other.scale;
+ precision = other.precision;
+ flags = other.flags;
+ origDouble = other.origDouble;
+ origDelta = other.origDelta;
+ isApproximate = other.isApproximate;
+ exponent = other.exponent;
+}
+
+void DecimalQuantity::clear() {
+ lReqPos = 0;
+ rReqPos = 0;
+ flags = 0;
+ setBcdToZero(); // sets scale, precision, hasDouble, origDouble, origDelta, and BCD data
+}
+
+void DecimalQuantity::setMinInteger(int32_t minInt) {
+ // Validation should happen outside of DecimalQuantity, e.g., in the Precision class.
+ U_ASSERT(minInt >= 0);
+
+ // 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
+ lReqPos = minInt;
+}
+
+void DecimalQuantity::setMinFraction(int32_t minFrac) {
+ // Validation should happen outside of DecimalQuantity, e.g., in the Precision class.
+ U_ASSERT(minFrac >= 0);
+
+ // Save values into internal state
+ // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE
+ rReqPos = -minFrac;
+}
+
+void DecimalQuantity::applyMaxInteger(int32_t maxInt) {
+ // Validation should happen outside of DecimalQuantity, e.g., in the Precision class.
+ U_ASSERT(maxInt >= 0);
+
+ if (precision == 0) {
+ return;
+ }
+
+ if (maxInt <= scale) {
+ setBcdToZero();
+ return;
+ }
+
+ int32_t magnitude = getMagnitude();
+ if (maxInt <= magnitude) {
+ popFromLeft(magnitude - maxInt + 1);
+ compact();
+ }
+}
+
+uint64_t DecimalQuantity::getPositionFingerprint() const {
+ uint64_t fingerprint = 0;
+ fingerprint ^= (lReqPos << 16);
+ fingerprint ^= (static_cast<uint64_t>(rReqPos) << 32);
+ return fingerprint;
+}
+
+void DecimalQuantity::roundToIncrement(double roundingIncrement, RoundingMode roundingMode,
+ UErrorCode& status) {
+ // Do not call this method with an increment having only a 1 or a 5 digit!
+ // Use a more efficient call to either roundToMagnitude() or roundToNickel().
+ // Check a few popular rounding increments; a more thorough check is in Java.
+ U_ASSERT(roundingIncrement != 0.01);
+ U_ASSERT(roundingIncrement != 0.05);
+ U_ASSERT(roundingIncrement != 0.1);
+ U_ASSERT(roundingIncrement != 0.5);
+ U_ASSERT(roundingIncrement != 1);
+ U_ASSERT(roundingIncrement != 5);
+
+ DecNum incrementDN;
+ incrementDN.setTo(roundingIncrement, status);
+ if (U_FAILURE(status)) { return; }
+
+ // Divide this DecimalQuantity by the increment, round, then multiply back.
+ divideBy(incrementDN, status);
+ if (U_FAILURE(status)) { return; }
+ roundToMagnitude(0, roundingMode, status);
+ if (U_FAILURE(status)) { return; }
+ multiplyBy(incrementDN, status);
+ if (U_FAILURE(status)) { return; }
+}
+
+void DecimalQuantity::multiplyBy(const DecNum& multiplicand, UErrorCode& status) {
+ if (isZeroish()) {
+ return;
+ }
+ // 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 (isZeroish()) {
+ 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 {
+ U_ASSERT(precision != 0);
+ return scale + precision - 1;
+}
+
+bool DecimalQuantity::adjustMagnitude(int32_t delta) {
+ if (precision != 0) {
+ // 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 {
+ // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
+ // See the comment at the top of this file explaining the "isApproximate" field.
+ U_ASSERT(!isApproximate);
+
+ switch (operand) {
+ case PLURAL_OPERAND_I:
+ // Invert the negative sign if necessary
+ return static_cast<double>(isNegative() ? -toLong(true) : toLong(true));
+ case PLURAL_OPERAND_F:
+ return static_cast<double>(toFractionLong(true));
+ case PLURAL_OPERAND_T:
+ return static_cast<double>(toFractionLong(false));
+ case PLURAL_OPERAND_V:
+ return fractionCount();
+ case PLURAL_OPERAND_W:
+ return fractionCountWithoutTrailingZeros();
+ case PLURAL_OPERAND_E:
+ return static_cast<double>(getExponent());
+ default:
+ return std::abs(toDouble());
+ }
+}
+
+int32_t DecimalQuantity::getExponent() const {
+ return exponent;
+}
+
+void DecimalQuantity::adjustExponent(int delta) {
+ exponent = exponent + delta;
+}
+
+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.
+ U_ASSERT(!isApproximate);
+
+ int32_t magnitude = scale + precision;
+ int32_t result = (lReqPos > magnitude) ? lReqPos : magnitude;
+ return result - 1;
+}
+
+int32_t DecimalQuantity::getLowerDisplayMagnitude() 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);
+
+ int32_t magnitude = scale;
+ int32_t result = (rReqPos < magnitude) ? rReqPos : magnitude;
+ return result;
+}
+
+int8_t DecimalQuantity::getDigit(int32_t magnitude) const {
+ // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
+ // See the comment at the top of this file explaining the "isApproximate" field.
+ U_ASSERT(!isApproximate);
+
+ return getDigitPos(magnitude - scale);
+}
+
+int32_t DecimalQuantity::fractionCount() const {
+ int32_t fractionCountWithExponent = -getLowerDisplayMagnitude() - exponent;
+ return fractionCountWithExponent > 0 ? fractionCountWithExponent : 0;
+}
+
+int32_t DecimalQuantity::fractionCountWithoutTrailingZeros() const {
+ int32_t fractionCountWithExponent = -scale - exponent;
+ return fractionCountWithExponent > 0 ? fractionCountWithExponent : 0; // max(-fractionCountWithExponent, 0)
+}
+
+bool DecimalQuantity::isNegative() const {
+ return (flags & NEGATIVE_FLAG) != 0;
+}
+
+Signum DecimalQuantity::signum() const {
+ bool isZero = (isZeroish() && !isInfinite());
+ bool isNeg = isNegative();
+ if (isZero && isNeg) {
+ return SIGNUM_NEG_ZERO;
+ } else if (isZero) {
+ return SIGNUM_POS_ZERO;
+ } else if (isNeg) {
+ return SIGNUM_NEG;
+ } else {
+ return SIGNUM_POS;
+ }
+}
+
+bool DecimalQuantity::isInfinite() const {
+ return (flags & INFINITY_FLAG) != 0;
+}
+
+bool DecimalQuantity::isNaN() const {
+ return (flags & NAN_FLAG) != 0;
+}
+
+bool DecimalQuantity::isZeroish() const {
+ return precision == 0;
+}
+
+DecimalQuantity &DecimalQuantity::setToInt(int32_t n) {
+ setBcdToZero();
+ flags = 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;
+ }
+ if (n != 0) {
+ _setToInt(n);
+ compact();
+ }
+ return *this;
+}
+
+void DecimalQuantity::_setToInt(int32_t n) {
+ if (n == INT32_MIN) {
+ readLongToBcd(-static_cast<int64_t>(n));
+ } else {
+ readIntToBcd(n);
+ }
+}
+
+DecimalQuantity &DecimalQuantity::setToLong(int64_t n) {
+ setBcdToZero();
+ flags = 0;
+ if (n < 0 && n > INT64_MIN) {
+ flags |= NEGATIVE_FLAG;
+ n = -n;
+ }
+ if (n != 0) {
+ _setToLong(n);
+ compact();
+ }
+ return *this;
+}
+
+void DecimalQuantity::_setToLong(int64_t n) {
+ if (n == INT64_MIN) {
+ 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<int32_t>(n));
+ } else {
+ readLongToBcd(n);
+ }
+}
+
+DecimalQuantity &DecimalQuantity::setToDouble(double n) {
+ setBcdToZero();
+ flags = 0;
+ // signbit() from <math.h> handles +0.0 vs -0.0
+ if (std::signbit(n)) {
+ flags |= NEGATIVE_FLAG;
+ n = -n;
+ }
+ if (std::isnan(n) != 0) {
+ flags |= NAN_FLAG;
+ } else if (std::isfinite(n) == 0) {
+ flags |= INFINITY_FLAG;
+ } else if (n != 0) {
+ _setToDoubleFast(n);
+ compact();
+ }
+ return *this;
+}
+
+void DecimalQuantity::_setToDoubleFast(double n) {
+ isApproximate = true;
+ origDouble = n;
+ origDelta = 0;
+
+ // Make sure the double is an IEEE 754 double. If not, fall back to the slow path right now.
+ // TODO: Make a fast path for other types of doubles.
+ if (!std::numeric_limits<double>::is_iec559) {
+ convertToAccurateDouble();
+ return;
+ }
+
+ // To get the bits from the double, use memcpy, which takes care of endianness.
+ uint64_t ieeeBits;
+ uprv_memcpy(&ieeeBits, &n, sizeof(n));
+ int32_t exponent = static_cast<int32_t>((ieeeBits & 0x7ff0000000000000L) >> 52) - 0x3ff;
+
+ // Not all integers can be represented exactly for exponent > 52
+ if (exponent <= 52 && static_cast<int64_t>(n) == n) {
+ _setToLong(static_cast<int64_t>(n));
+ return;
+ }
+
+ if (exponent == -1023 || exponent == 1024) {
+ // The extreme values of exponent are special; use slow path.
+ convertToAccurateDouble();
+ return;
+ }
+
+ // 3.3219... is log2(10)
+ auto fracLength = static_cast<int32_t> ((52 - exponent) / 3.32192809488736234787031942948939017586);
+ if (fracLength >= 0) {
+ int32_t i = fracLength;
+ // 1e22 is the largest exact double.
+ for (; i >= 22; i -= 22) n *= 1e22;
+ n *= DOUBLE_MULTIPLIERS[i];
+ } else {
+ int32_t i = fracLength;
+ // 1e22 is the largest exact double.
+ for (; i <= -22; i += 22) n /= 1e22;
+ n /= DOUBLE_MULTIPLIERS[-i];
+ }
+ auto result = static_cast<int64_t>(uprv_round(n));
+ if (result != 0) {
+ _setToLong(result);
+ scale -= fracLength;
+ }
+}
+
+void DecimalQuantity::convertToAccurateDouble() {
+ U_ASSERT(origDouble != 0);
+ int32_t delta = origDelta;
+
+ // Call the slow oracle function (Double.toString in Java, DoubleToAscii in C++).
+ char buffer[DoubleToStringConverter::kBase10MaximalLength + 1];
+ bool sign; // unused; always positive
+ int32_t length;
+ int32_t point;
+ DoubleToStringConverter::DoubleToAscii(
+ origDouble,
+ DoubleToStringConverter::DtoaMode::SHORTEST,
+ 0,
+ buffer,
+ sizeof(buffer),
+ &sign,
+ &length,
+ &point
+ );
+
+ setBcdToZero();
+ readDoubleConversionToBcd(buffer, length, point);
+ scale += delta;
+ explicitExactDouble = true;
+}
+
+DecimalQuantity &DecimalQuantity::setToDecNumber(StringPiece n, UErrorCode& status) {
+ setBcdToZero();
+ flags = 0;
+
+ // Compute the decNumber representation
+ DecNum decnum;
+ decnum.setTo(n, status);
+
+ _setToDecNum(decnum, status);
+ return *this;
+}
+
+DecimalQuantity& DecimalQuantity::setToDecNum(const DecNum& decnum, UErrorCode& status) {
+ setBcdToZero();
+ flags = 0;
+
+ _setToDecNum(decnum, status);
+ return *this;
+}
+
+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 = exponent + scale + precision - 1;
+ if (truncateIfOverflow) {
+ upperMagnitude = std::min(upperMagnitude, 17);
+ }
+ for (int32_t magnitude = upperMagnitude; magnitude >= 0; magnitude--) {
+ result = result * 10 + getDigitPos(magnitude - scale - exponent);
+ }
+ if (isNegative()) {
+ return static_cast<int64_t>(0LL - result); // i.e., -result
+ }
+ return static_cast<int64_t>(result);
+}
+
+uint64_t DecimalQuantity::toFractionLong(bool includeTrailingZeros) const {
+ uint64_t result = 0L;
+ int32_t magnitude = -1 - exponent;
+ int32_t lowerMagnitude = scale;
+ 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;
+}
+
+bool DecimalQuantity::fitsInLong(bool ignoreFraction) const {
+ if (isInfinite() || isNaN()) {
+ return false;
+ }
+ if (isZeroish()) {
+ return true;
+ }
+ if (exponent + 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;
+ } else if (isInfinite()) {
+ return isNegative() ? -INFINITY : INFINITY;
+ }
+
+ // 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<const uint16_t*>(numberString.getBuffer()),
+ numberString.length(),
+ &count);
+}
+
+void DecimalQuantity::toDecNum(DecNum& output, UErrorCode& status) const {
+ // Special handling for zero
+ if (precision == 0) {
+ output.setTo("0", status);
+ }
+
+ // 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<uint8_t, 20> ubcd(precision);
+ for (int32_t m = 0; m < precision; m++) {
+ ubcd[precision - m - 1] = static_cast<uint8_t>(getDigitPos(m));
+ }
+ output.setTo(ubcd.getAlias(), precision, scale, isNegative(), status);
+}
+
+void DecimalQuantity::truncate() {
+ if (scale < 0) {
+ shiftRight(-scale);
+ scale = 0;
+ compact();
+ }
+}
+
+void DecimalQuantity::roundToNickel(int32_t magnitude, RoundingMode roundingMode, UErrorCode& status) {
+ roundToMagnitude(magnitude, roundingMode, true, status);
+}
+
+void DecimalQuantity::roundToMagnitude(int32_t magnitude, RoundingMode roundingMode, UErrorCode& status) {
+ roundToMagnitude(magnitude, roundingMode, false, status);
+}
+
+void DecimalQuantity::roundToMagnitude(int32_t magnitude, RoundingMode roundingMode, bool nickel, UErrorCode& status) {
+ // The position in the BCD at which rounding will be performed; digits to the right of position
+ // will be rounded away.
+ int position = safeSubtract(magnitude, scale);
+
+ // "trailing" = least significant digit to the left of rounding
+ int8_t trailingDigit = getDigitPos(position);
+
+ if (position <= 0 && !isApproximate && (!nickel || trailingDigit == 0 || trailingDigit == 5)) {
+ // All digits are to the left of the rounding magnitude.
+ } else if (precision == 0) {
+ // No rounding for zero.
+ } else {
+ // Perform rounding logic.
+ // "leading" = most significant digit to the right of rounding
+ int8_t leadingDigit = getDigitPos(safeSubtract(position, 1));
+
+ // Compute which section of the number we are in.
+ // EDGE means we are at the bottom or top edge, like 1.000 or 1.999 (used by doubles)
+ // LOWER means we are between the bottom edge and the midpoint, like 1.391
+ // MIDPOINT means we are exactly in the middle, like 1.500
+ // UPPER means we are between the midpoint and the top edge, like 1.916
+ roundingutils::Section section;
+ if (!isApproximate) {
+ if (nickel && trailingDigit != 2 && trailingDigit != 7) {
+ // Nickel rounding, and not at .02x or .07x
+ if (trailingDigit < 2) {
+ // .00, .01 => down to .00
+ section = roundingutils::SECTION_LOWER;
+ } else if (trailingDigit < 5) {
+ // .03, .04 => up to .05
+ section = roundingutils::SECTION_UPPER;
+ } else if (trailingDigit < 7) {
+ // .05, .06 => down to .05
+ section = roundingutils::SECTION_LOWER;
+ } else {
+ // .08, .09 => up to .10
+ section = roundingutils::SECTION_UPPER;
+ }
+ } else if (leadingDigit < 5) {
+ // Includes nickel rounding .020-.024 and .070-.074
+ section = roundingutils::SECTION_LOWER;
+ } else if (leadingDigit > 5) {
+ // Includes nickel rounding .026-.029 and .076-.079
+ section = roundingutils::SECTION_UPPER;
+ } else {
+ // Includes nickel rounding .025 and .075
+ section = roundingutils::SECTION_MIDPOINT;
+ for (int p = safeSubtract(position, 2); p >= 0; p--) {
+ if (getDigitPos(p) != 0) {
+ section = roundingutils::SECTION_UPPER;
+ break;
+ }
+ }
+ }
+ } else {
+ int32_t p = safeSubtract(position, 2);
+ int32_t minP = uprv_max(0, precision - 14);
+ if (leadingDigit == 0 && (!nickel || trailingDigit == 0 || trailingDigit == 5)) {
+ section = roundingutils::SECTION_LOWER_EDGE;
+ for (; p >= minP; p--) {
+ if (getDigitPos(p) != 0) {
+ section = roundingutils::SECTION_LOWER;
+ break;
+ }
+ }
+ } else if (leadingDigit == 4 && (!nickel || trailingDigit == 2 || trailingDigit == 7)) {
+ section = roundingutils::SECTION_MIDPOINT;
+ for (; p >= minP; p--) {
+ if (getDigitPos(p) != 9) {
+ section = roundingutils::SECTION_LOWER;
+ break;
+ }
+ }
+ } else if (leadingDigit == 5 && (!nickel || trailingDigit == 2 || trailingDigit == 7)) {
+ section = roundingutils::SECTION_MIDPOINT;
+ for (; p >= minP; p--) {
+ if (getDigitPos(p) != 0) {
+ section = roundingutils::SECTION_UPPER;
+ break;
+ }
+ }
+ } else if (leadingDigit == 9 && (!nickel || trailingDigit == 4 || trailingDigit == 9)) {
+ section = roundingutils::SECTION_UPPER_EDGE;
+ for (; p >= minP; p--) {
+ if (getDigitPos(p) != 9) {
+ section = roundingutils::SECTION_UPPER;
+ break;
+ }
+ }
+ } else if (nickel && trailingDigit != 2 && trailingDigit != 7) {
+ // Nickel rounding, and not at .02x or .07x
+ if (trailingDigit < 2) {
+ // .00, .01 => down to .00
+ section = roundingutils::SECTION_LOWER;
+ } else if (trailingDigit < 5) {
+ // .03, .04 => up to .05
+ section = roundingutils::SECTION_UPPER;
+ } else if (trailingDigit < 7) {
+ // .05, .06 => down to .05
+ section = roundingutils::SECTION_LOWER;
+ } else {
+ // .08, .09 => up to .10
+ section = roundingutils::SECTION_UPPER;
+ }
+ } else if (leadingDigit < 5) {
+ // Includes nickel rounding .020-.024 and .070-.074
+ section = roundingutils::SECTION_LOWER;
+ } else {
+ // Includes nickel rounding .026-.029 and .076-.079
+ section = roundingutils::SECTION_UPPER;
+ }
+
+ bool roundsAtMidpoint = roundingutils::roundsAtMidpoint(roundingMode);
+ if (safeSubtract(position, 1) < precision - 14 ||
+ (roundsAtMidpoint && section == roundingutils::SECTION_MIDPOINT) ||
+ (!roundsAtMidpoint && section < 0 /* i.e. at upper or lower edge */)) {
+ // Oops! This means that we have to get the exact representation of the double,
+ // because the zone of uncertainty is along the rounding boundary.
+ convertToAccurateDouble();
+ roundToMagnitude(magnitude, roundingMode, nickel, status); // start over
+ return;
+ }
+
+ // Turn off the approximate double flag, since the value is now confirmed to be exact.
+ isApproximate = false;
+ origDouble = 0.0;
+ origDelta = 0;
+
+ if (position <= 0 && (!nickel || trailingDigit == 0 || trailingDigit == 5)) {
+ // All digits are to the left of the rounding magnitude.
+ return;
+ }
+
+ // Good to continue rounding.
+ if (section == -1) { section = roundingutils::SECTION_LOWER; }
+ if (section == -2) { section = roundingutils::SECTION_UPPER; }
+ }
+
+ // Nickel rounding "half even" goes to the nearest whole (away from the 5).
+ bool isEven = nickel
+ ? (trailingDigit < 2 || trailingDigit > 7
+ || (trailingDigit == 2 && section != roundingutils::SECTION_UPPER)
+ || (trailingDigit == 7 && section == roundingutils::SECTION_UPPER))
+ : (trailingDigit % 2) == 0;
+
+ bool roundDown = roundingutils::getRoundingDirection(isEven,
+ isNegative(),
+ section,
+ roundingMode,
+ status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // Perform truncation
+ if (position >= precision) {
+ setBcdToZero();
+ scale = magnitude;
+ } else {
+ shiftRight(position);
+ }
+
+ if (nickel) {
+ if (trailingDigit < 5 && roundDown) {
+ setDigitPos(0, 0);
+ compact();
+ return;
+ } else if (trailingDigit >= 5 && !roundDown) {
+ setDigitPos(0, 9);
+ trailingDigit = 9;
+ // do not return: use the bubbling logic below
+ } else {
+ setDigitPos(0, 5);
+ // compact not necessary: digit at position 0 is nonzero
+ return;
+ }
+ }
+
+ // Bubble the result to the higher digits
+ if (!roundDown) {
+ if (trailingDigit == 9) {
+ int bubblePos = 0;
+ // Note: in the long implementation, the most digits BCD can have at this point is
+ // 15, so bubblePos <= 15 and getDigitPos(bubblePos) is safe.
+ for (; getDigitPos(bubblePos) == 9; bubblePos++) {}
+ shiftRight(bubblePos); // shift off the trailing 9s
+ }
+ int8_t digit0 = getDigitPos(0);
+ U_ASSERT(digit0 != 9);
+ setDigitPos(0, static_cast<int8_t>(digit0 + 1));
+ precision += 1; // in case an extra digit got added
+ }
+
+ compact();
+ }
+}
+
+void DecimalQuantity::roundToInfinity() {
+ if (isApproximate) {
+ convertToAccurateDouble();
+ }
+}
+
+void DecimalQuantity::appendDigit(int8_t value, int32_t leadingZeros, bool appendAsInteger) {
+ U_ASSERT(leadingZeros >= 0);
+
+ // Zero requires special handling to maintain the invariant that the least-significant digit
+ // in the BCD is nonzero.
+ if (value == 0) {
+ if (appendAsInteger && precision != 0) {
+ scale += leadingZeros + 1;
+ }
+ return;
+ }
+
+ // Deal with trailing zeros
+ if (scale > 0) {
+ leadingZeros += scale;
+ if (appendAsInteger) {
+ scale = 0;
+ }
+ }
+
+ // Append digit
+ shiftLeft(leadingZeros + 1);
+ setDigitPos(0, value);
+
+ // Fix scale if in integer mode
+ if (appendAsInteger) {
+ scale += leadingZeros + 1;
+ }
+}
+
+UnicodeString DecimalQuantity::toPlainString() const {
+ U_ASSERT(!isApproximate);
+ UnicodeString sb;
+ if (isNegative()) {
+ sb.append(u'-');
+ }
+ if (precision == 0) {
+ sb.append(u'0');
+ return sb;
+ }
+ int32_t upper = scale + precision + exponent - 1;
+ int32_t lower = scale + exponent;
+ if (upper < lReqPos - 1) {
+ upper = lReqPos - 1;
+ }
+ if (lower > rReqPos) {
+ lower = rReqPos;
+ }
+ int32_t p = upper;
+ if (p < 0) {
+ sb.append(u'0');
+ }
+ for (; p >= 0; p--) {
+ sb.append(u'0' + getDigitPos(p - scale - exponent));
+ }
+ if (lower < 0) {
+ sb.append(u'.');
+ }
+ for(; p >= lower; p--) {
+ sb.append(u'0' + getDigitPos(p - scale - exponent));
+ }
+ 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;
+ }
+ int32_t upperPos = precision - 1;
+ int32_t lowerPos = 0;
+ 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 + exponent;
+ if (_scale == INT32_MIN) {
+ result.append({u"-2147483648", -1});
+ return result;
+ } else 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 ///
+////////////////////////////////////////////////////
+
+int8_t DecimalQuantity::getDigitPos(int32_t position) const {
+ if (usingBytes) {
+ if (position < 0 || position >= precision) { return 0; }
+ return fBCD.bcdBytes.ptr[position];
+ } else {
+ if (position < 0 || position >= 16) { return 0; }
+ return (int8_t) ((fBCD.bcdLong >> (position * 4)) & 0xf);
+ }
+}
+
+void DecimalQuantity::setDigitPos(int32_t position, int8_t value) {
+ U_ASSERT(position >= 0);
+ if (usingBytes) {
+ ensureCapacity(position + 1);
+ fBCD.bcdBytes.ptr[position] = value;
+ } else if (position >= 16) {
+ switchStorage();
+ ensureCapacity(position + 1);
+ fBCD.bcdBytes.ptr[position] = value;
+ } else {
+ int shift = position * 4;
+ fBCD.bcdLong = (fBCD.bcdLong & ~(0xfL << shift)) | ((long) value << shift);
+ }
+}
+
+void DecimalQuantity::shiftLeft(int32_t numDigits) {
+ if (!usingBytes && precision + numDigits > 16) {
+ switchStorage();
+ }
+ if (usingBytes) {
+ ensureCapacity(precision + numDigits);
+ int i = precision + numDigits - 1;
+ for (; i >= numDigits; i--) {
+ fBCD.bcdBytes.ptr[i] = fBCD.bcdBytes.ptr[i - numDigits];
+ }
+ for (; i >= 0; i--) {
+ fBCD.bcdBytes.ptr[i] = 0;
+ }
+ } else {
+ fBCD.bcdLong <<= (numDigits * 4);
+ }
+ scale -= numDigits;
+ precision += numDigits;
+}
+
+void DecimalQuantity::shiftRight(int32_t numDigits) {
+ if (usingBytes) {
+ int i = 0;
+ for (; i < precision - numDigits; i++) {
+ fBCD.bcdBytes.ptr[i] = fBCD.bcdBytes.ptr[i + numDigits];
+ }
+ for (; i < precision; i++) {
+ fBCD.bcdBytes.ptr[i] = 0;
+ }
+ } else {
+ fBCD.bcdLong >>= (numDigits * 4);
+ }
+ scale += numDigits;
+ precision -= numDigits;
+}
+
+void DecimalQuantity::popFromLeft(int32_t numDigits) {
+ U_ASSERT(numDigits <= precision);
+ if (usingBytes) {
+ int i = precision - 1;
+ for (; i >= precision - numDigits; i--) {
+ fBCD.bcdBytes.ptr[i] = 0;
+ }
+ } else {
+ fBCD.bcdLong &= (static_cast<uint64_t>(1) << ((precision - numDigits) * 4)) - 1;
+ }
+ precision -= numDigits;
+}
+
+void DecimalQuantity::setBcdToZero() {
+ if (usingBytes) {
+ uprv_free(fBCD.bcdBytes.ptr);
+ fBCD.bcdBytes.ptr = nullptr;
+ usingBytes = false;
+ }
+ fBCD.bcdLong = 0L;
+ scale = 0;
+ precision = 0;
+ isApproximate = false;
+ origDouble = 0;
+ origDelta = 0;
+ exponent = 0;
+}
+
+void DecimalQuantity::readIntToBcd(int32_t n) {
+ U_ASSERT(n != 0);
+ // ints always fit inside the long implementation.
+ uint64_t result = 0L;
+ int i = 16;
+ for (; n != 0; n /= 10, i--) {
+ result = (result >> 4) + ((static_cast<uint64_t>(n) % 10) << 60);
+ }
+ U_ASSERT(!usingBytes);
+ fBCD.bcdLong = result >> (i * 4);
+ scale = 0;
+ precision = 16 - i;
+}
+
+void DecimalQuantity::readLongToBcd(int64_t n) {
+ U_ASSERT(n != 0);
+ if (n >= 10000000000000000L) {
+ ensureCapacity();
+ int i = 0;
+ for (; n != 0L; n /= 10L, i++) {
+ fBCD.bcdBytes.ptr[i] = static_cast<int8_t>(n % 10);
+ }
+ U_ASSERT(usingBytes);
+ scale = 0;
+ precision = i;
+ } else {
+ uint64_t result = 0L;
+ int i = 16;
+ for (; n != 0L; n /= 10L, i--) {
+ result = (result >> 4) + ((n % 10) << 60);
+ }
+ U_ASSERT(i >= 0);
+ U_ASSERT(!usingBytes);
+ fBCD.bcdLong = result >> (i * 4);
+ scale = 0;
+ precision = 16 - i;
+ }
+}
+
+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++) {
+ fBCD.bcdBytes.ptr[i] = dn->lsu[i];
+ }
+ } else {
+ uint64_t result = 0L;
+ for (int32_t i = 0; i < dn->digits; i++) {
+ result |= static_cast<uint64_t>(dn->lsu[i]) << (4 * i);
+ }
+ fBCD.bcdLong = result;
+ }
+ scale = dn->exponent;
+ precision = dn->digits;
+}
+
+void DecimalQuantity::readDoubleConversionToBcd(
+ const char* buffer, int32_t length, int32_t point) {
+ // NOTE: Despite the fact that double-conversion's API is called
+ // "DoubleToAscii", they actually use '0' (as opposed to u8'0').
+ if (length > 16) {
+ ensureCapacity(length);
+ for (int32_t i = 0; i < length; i++) {
+ fBCD.bcdBytes.ptr[i] = buffer[length-i-1] - '0';
+ }
+ } else {
+ uint64_t result = 0L;
+ for (int32_t i = 0; i < length; i++) {
+ result |= static_cast<uint64_t>(buffer[length-i-1] - '0') << (4 * i);
+ }
+ fBCD.bcdLong = result;
+ }
+ scale = point - length;
+ precision = length;
+}
+
+void DecimalQuantity::compact() {
+ if (usingBytes) {
+ int32_t delta = 0;
+ for (; delta < precision && fBCD.bcdBytes.ptr[delta] == 0; delta++);
+ if (delta == precision) {
+ // Number is zero
+ setBcdToZero();
+ return;
+ } else {
+ // Remove trailing zeros
+ shiftRight(delta);
+ }
+
+ // Compute precision
+ int32_t leading = precision - 1;
+ for (; leading >= 0 && fBCD.bcdBytes.ptr[leading] == 0; leading--);
+ precision = leading + 1;
+
+ // Switch storage mechanism if possible
+ if (precision <= 16) {
+ switchStorage();
+ }
+
+ } else {
+ if (fBCD.bcdLong == 0L) {
+ // Number is zero
+ setBcdToZero();
+ return;
+ }
+
+ // Compact the number (remove trailing zeros)
+ // TODO: Use a more efficient algorithm here and below. There is a logarithmic one.
+ int32_t delta = 0;
+ for (; delta < precision && getDigitPos(delta) == 0; delta++);
+ fBCD.bcdLong >>= delta * 4;
+ scale += delta;
+
+ // Compute precision
+ int32_t leading = precision - 1;
+ for (; leading >= 0 && getDigitPos(leading) == 0; leading--);
+ precision = leading + 1;
+ }
+}
+
+void DecimalQuantity::ensureCapacity() {
+ ensureCapacity(40);
+}
+
+void DecimalQuantity::ensureCapacity(int32_t capacity) {
+ if (capacity == 0) { return; }
+ int32_t oldCapacity = usingBytes ? fBCD.bcdBytes.len : 0;
+ if (!usingBytes) {
+ // TODO: There is nothing being done to check for memory allocation failures.
+ // TODO: Consider indexing by nybbles instead of bytes in C++, so that we can
+ // make these arrays half the size.
+ fBCD.bcdBytes.ptr = static_cast<int8_t*>(uprv_malloc(capacity * sizeof(int8_t)));
+ fBCD.bcdBytes.len = capacity;
+ // Initialize the byte array to zeros (this is done automatically in Java)
+ uprv_memset(fBCD.bcdBytes.ptr, 0, capacity * sizeof(int8_t));
+ } else if (oldCapacity < capacity) {
+ auto bcd1 = static_cast<int8_t*>(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(bcd1 + oldCapacity, 0, (capacity - oldCapacity) * sizeof(int8_t));
+ uprv_free(fBCD.bcdBytes.ptr);
+ fBCD.bcdBytes.ptr = bcd1;
+ fBCD.bcdBytes.len = capacity * 2;
+ }
+ usingBytes = true;
+}
+
+void DecimalQuantity::switchStorage() {
+ if (usingBytes) {
+ // Change from bytes to long
+ uint64_t bcdLong = 0L;
+ for (int i = precision - 1; i >= 0; i--) {
+ bcdLong <<= 4;
+ bcdLong |= fBCD.bcdBytes.ptr[i];
+ }
+ uprv_free(fBCD.bcdBytes.ptr);
+ fBCD.bcdBytes.ptr = nullptr;
+ fBCD.bcdLong = bcdLong;
+ usingBytes = false;
+ } else {
+ // Change from long to bytes
+ // Copy the long into a local variable since it will get munged when we allocate the bytes
+ uint64_t bcdLong = fBCD.bcdLong;
+ ensureCapacity();
+ for (int i = 0; i < precision; i++) {
+ fBCD.bcdBytes.ptr[i] = static_cast<int8_t>(bcdLong & 0xf);
+ bcdLong >>= 4;
+ }
+ U_ASSERT(usingBytes);
+ }
+}
+
+void DecimalQuantity::copyBcdFrom(const DecimalQuantity &other) {
+ setBcdToZero();
+ if (other.usingBytes) {
+ ensureCapacity(other.precision);
+ uprv_memcpy(fBCD.bcdBytes.ptr, other.fBCD.bcdBytes.ptr, other.precision * sizeof(int8_t));
+ } else {
+ fBCD.bcdLong = other.fBCD.bcdLong;
+ }
+}
+
+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"; }
+ int32_t capacity = fBCD.bcdBytes.len;
+ if (precision > capacity) { return u"Precision exceeds length of byte array"; }
+ if (getDigitPos(precision - 1) == 0) { return u"Most significant digit is zero in byte mode"; }
+ if (getDigitPos(0) == 0) { return u"Least significant digit is zero in long mode"; }
+ for (int i = 0; i < precision; i++) {
+ if (getDigitPos(i) >= 10) { return u"Digit exceeding 10 in byte array"; }
+ if (getDigitPos(i) < 0) { return u"Digit below 0 in byte array"; }
+ }
+ for (int i = precision; i < capacity; i++) {
+ if (getDigitPos(i) != 0) { return u"Nonzero digits outside of range in byte array"; }
+ }
+ } else {
+ if (precision == 0 && fBCD.bcdLong != 0) {
+ return u"Value in bcdLong even though precision is zero";
+ }
+ if (precision > 16) { return u"Precision exceeds length of long"; }
+ if (precision != 0 && getDigitPos(precision - 1) == 0) {
+ return u"Most significant digit is zero in long mode";
+ }
+ if (precision != 0 && getDigitPos(0) == 0) {
+ return u"Least significant digit is zero in long mode";
+ }
+ for (int i = 0; i < precision; i++) {
+ if (getDigitPos(i) >= 10) { return u"Digit exceeding 10 in long"; }
+ if (getDigitPos(i) < 0) { return u"Digit below 0 in long (?!)"; }
+ }
+ for (int i = precision; i < 16; i++) {
+ if (getDigitPos(i) != 0) { return u"Nonzero digits outside of range in long"; }
+ }
+ }
+
+ // No error
+ return nullptr;
+}
+
+bool DecimalQuantity::operator==(const DecimalQuantity& other) const {
+ bool basicEquals =
+ scale == other.scale
+ && precision == other.precision
+ && flags == other.flags
+ && lReqPos == other.lReqPos
+ && rReqPos == other.rReqPos
+ && isApproximate == other.isApproximate;
+ if (!basicEquals) {
+ return false;
+ }
+
+ if (precision == 0) {
+ return true;
+ } else if (isApproximate) {
+ return origDouble == other.origDouble && origDelta == other.origDelta;
+ } else {
+ for (int m = getUpperDisplayMagnitude(); m >= getLowerDisplayMagnitude(); m--) {
+ if (getDigit(m) != other.getDigit(m)) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
+
+UnicodeString DecimalQuantity::toString() const {
+ MaybeStackArray<char, 30> digits(precision + 1);
+ for (int32_t i = 0; i < precision; i++) {
+ digits[i] = getDigitPos(precision - i - 1) + '0';
+ }
+ digits[precision] = 0; // terminate buffer
+ char buffer8[100];
+ snprintf(
+ buffer8,
+ sizeof(buffer8),
+ "<DecimalQuantity %d:%d %s %s%s%s%d>",
+ lReqPos,
+ rReqPos,
+ (usingBytes ? "bytes" : "long"),
+ (isNegative() ? "-" : ""),
+ (precision == 0 ? "0" : digits.getAlias()),
+ "E",
+ scale);
+ return UnicodeString(buffer8, -1, US_INV);
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_decimalquantity.h b/contrib/libs/icu/i18n/number_decimalquantity.h
index d9b35c0336..983e2b98f3 100644
--- a/contrib/libs/icu/i18n/number_decimalquantity.h
+++ b/contrib/libs/icu/i18n/number_decimalquantity.h
@@ -1,526 +1,526 @@
-// © 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_DECIMALQUANTITY_H__
-#define __NUMBER_DECIMALQUANTITY_H__
-
-#include <cstdint>
-#include "unicode/umachine.h"
-#include "standardplural.h"
-#include "plurrule_impl.h"
-#include "number_types.h"
-
-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.
- *
- * <p>By design, this is NOT IMMUTABLE and NOT THREAD SAFE. It is intended to be an intermediate
- * object holding state during a pass through the decimal formatting pipeline.
- *
- * <p>Represents numbers and digit display properties using Binary Coded Decimal (BCD).
- *
- * <p>Java has multiple implementations for testing, but C++ has only one implementation.
- */
-class U_I18N_API DecimalQuantity : public IFixedDecimal, public UMemory {
- public:
- /** Copy constructor. */
- DecimalQuantity(const DecimalQuantity &other);
-
- /** Move constructor. */
- DecimalQuantity(DecimalQuantity &&src) U_NOEXCEPT;
-
- DecimalQuantity();
-
- ~DecimalQuantity() override;
-
- /**
- * Sets this instance to be equal to another instance.
- *
- * @param other The instance to copy from.
- */
- DecimalQuantity &operator=(const DecimalQuantity &other);
-
- /** Move assignment */
- DecimalQuantity &operator=(DecimalQuantity&& src) U_NOEXCEPT;
-
- /**
- * Sets the minimum integer digits that this {@link DecimalQuantity} should generate.
- * This method does not perform rounding.
- *
- * @param minInt The minimum number of integer digits.
- */
- void setMinInteger(int32_t minInt);
-
- /**
- * Sets the minimum fraction digits that this {@link DecimalQuantity} should generate.
- * This method does not perform rounding.
- *
- * @param minFrac The minimum number of fraction digits.
- */
- void setMinFraction(int32_t minFrac);
-
- /**
- * Truncates digits from the upper magnitude of the number in order to satisfy the
- * specified maximum number of integer digits.
- *
- * @param maxInt The maximum number of integer digits.
- */
- void applyMaxInteger(int32_t maxInt);
-
- /**
- * Rounds the number to a specified interval, such as 0.05.
- *
- * <p>If rounding to a power of ten, use the more efficient {@link #roundToMagnitude} instead.
- *
- * @param roundingIncrement The increment to which to round.
- * @param roundingMode The {@link RoundingMode} to use if rounding is necessary.
- */
- void roundToIncrement(double roundingIncrement, RoundingMode roundingMode,
- UErrorCode& status);
-
- /** Removes all fraction digits. */
- void truncate();
-
- /**
- * Rounds the number to the nearest multiple of 5 at the specified magnitude.
- * For example, when magnitude == -2, this performs rounding to the nearest 0.05.
- *
- * @param magnitude The magnitude at which the digit should become either 0 or 5.
- * @param roundingMode Rounding strategy.
- */
- void roundToNickel(int32_t magnitude, RoundingMode roundingMode, UErrorCode& status);
-
- /**
- * Rounds the number to a specified magnitude (power of ten).
- *
- * @param roundingMagnitude The power of ten to which to round. For example, a value of -2 will
- * round to 2 decimal places.
- * @param roundingMode The {@link RoundingMode} to use if rounding is necessary.
- */
- void roundToMagnitude(int32_t magnitude, RoundingMode roundingMode, UErrorCode& status);
-
- /**
- * Rounds the number to an infinite number of decimal points. This has no effect except for
- * forcing the double in {@link DecimalQuantity_AbstractBCD} to adopt its exact representation.
- */
- void roundToInfinity();
-
- /**
- * 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 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.
- */
- bool adjustMagnitude(int32_t delta);
-
- /**
- * @return The power of ten corresponding to the most significant nonzero digit.
- * The number must not be zero.
- */
- int32_t getMagnitude() const;
-
- /**
- * @return The value of the (suppressed) exponent after the number has been
- * put into a notation with exponents (ex: compact, scientific). Ex: given
- * the number 1000 as "1K" / "1E3", the return value will be 3 (positive).
- */
- int32_t getExponent() const;
-
- /**
- * Adjusts the value for the (suppressed) exponent stored when using
- * notation with exponents (ex: compact, scientific).
- *
- * <p>Adjusting the exponent is decoupled from {@link #adjustMagnitude} in
- * order to allow flexibility for {@link StandardPlural} to be selected in
- * formatting (ex: for compact notation) either with or without the exponent
- * applied in the value of the number.
- * @param delta
- * The value to adjust the exponent by.
- */
- void adjustExponent(int32_t delta);
-
- /**
- * @return Whether the value represented by this {@link DecimalQuantity} is
- * zero, infinity, or NaN.
- */
- bool isZeroish() const;
-
- /** @return Whether the value represented by this {@link DecimalQuantity} is less than zero. */
- bool isNegative() const;
-
- /** @return The appropriate value from the Signum enum. */
- Signum signum() const;
-
- /** @return Whether the value represented by this {@link DecimalQuantity} is infinite. */
- bool isInfinite() const U_OVERRIDE;
-
- /** @return Whether the value represented by this {@link DecimalQuantity} is not a number. */
- bool isNaN() const U_OVERRIDE;
-
- /**
- * Note: this method incorporates the value of {@code exponent}
- * (for cases such as compact notation) to return the proper long value
- * represented by the result.
- * @param truncateIfOverflow if false and the number does NOT fit, fails with an assertion error.
- */
- int64_t toLong(bool truncateIfOverflow = false) const;
-
- /**
- * Note: this method incorporates the value of {@code exponent}
- * (for cases such as compact notation) to return the proper long value
- * represented by the result.
- */
- 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);
-
- DecimalQuantity &setToDouble(double n);
-
- /** decNumber is similar to BigDecimal in Java. */
- DecimalQuantity &setToDecNumber(StringPiece n, UErrorCode& status);
-
- /** 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
- * by this DecimalQuantity.
- *
- * <p>The primary use of this method is to construct numbers during a parsing loop. It allows
- * parsing to take advantage of the digit list infrastructure primarily designed for formatting.
- *
- * @param value The digit to append.
- * @param leadingZeros The number of zeros to append before the digit. For example, if the value
- * in this instance starts as 12.3, and you append a 4 with 1 leading zero, the value becomes
- * 12.304.
- * @param appendAsInteger If true, increase the magnitude of existing digits to make room for the
- * new digit. If false, append to the end like a fraction digit. If true, there must not be
- * any fraction digits already in the number.
- * @internal
- * @deprecated This API is ICU internal only.
- */
- void appendDigit(int8_t value, int32_t leadingZeros, bool appendAsInteger);
-
- 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.
- *
- * @param magnitude The magnitude of the digit.
- * @return The digit at the specified magnitude.
- */
- int8_t getDigit(int32_t magnitude) const;
-
- /**
- * Gets the largest power of ten that needs to be displayed. The value returned by this function
- * will be bounded between minInt and maxInt.
- *
- * @return The highest-magnitude digit to be displayed.
- */
- int32_t getUpperDisplayMagnitude() const;
-
- /**
- * Gets the smallest power of ten that needs to be displayed. The value returned by this function
- * will be bounded between -minFrac and -maxFrac.
- *
- * @return The lowest-magnitude digit to be displayed.
- */
- int32_t getLowerDisplayMagnitude() const;
-
- int32_t fractionCount() const;
-
- int32_t fractionCountWithoutTrailingZeros() const;
-
- void clear();
-
- /** This method is for internal testing only. */
- uint64_t getPositionFingerprint() const;
-
-// /**
-// * If the given {@link FieldPosition} is a {@link UFieldPosition}, populates it with the fraction
-// * length and fraction long value. If the argument is not a {@link UFieldPosition}, nothing
-// * happens.
-// *
-// * @param fp The {@link UFieldPosition} to populate.
-// */
-// void populateUFieldPosition(FieldPosition fp);
-
- /**
- * Checks whether the bytes stored in this instance are all valid. For internal unit testing only.
- *
- * @return An error message if this instance is invalid, or null if this instance is healthy.
- */
- const char16_t* checkHealth() const;
-
- UnicodeString toString() const;
-
- /** Returns the string in standard exponential notation. */
- UnicodeString toScientificString() const;
-
- /** Returns the string without exponential notation. Slightly slower than toScientificString(). */
- UnicodeString toPlainString() const;
-
- /** Visible for testing */
- inline bool isUsingBytes() { return usingBytes; }
-
- /** 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
- * object represents the number "3.14", the BCD will be "0x314" and the scale will be -2.
- *
- * <p>Note that in {@link java.math.BigDecimal}, the scale is defined differently: the number of
- * digits after the decimal place, which is the negative of our definition of scale.
- */
- int32_t scale;
-
- /**
- * The number of digits in the BCD. For example, "1007" has BCD "0x1007" and precision 4. The
- * maximum precision is 16 since a long can hold only 16 digits.
- *
- * <p>This value must be re-calculated whenever the value in bcd changes by using {@link
- * #computePrecisionAndCompact()}.
- */
- int32_t precision;
-
- /**
- * A bitmask of properties relating to the number represented by this object.
- *
- * @see #NEGATIVE_FLAG
- * @see #INFINITY_FLAG
- * @see #NAN_FLAG
- */
- int8_t flags;
-
- // The following three fields relate to the double-to-ascii fast path algorithm.
- // When a double is given to DecimalQuantityBCD, it is converted to using a fast algorithm. The
- // fast algorithm guarantees correctness to only the first ~12 digits of the double. The process
- // of rounding the number ensures that the converted digits are correct, falling back to a slow-
- // path algorithm if required. Therefore, if a DecimalQuantity is constructed from a double, it
- // is *required* that roundToMagnitude(), roundToIncrement(), or roundToInfinity() is called. If
- // you don't round, assertions will fail in certain other methods if you try calling them.
-
- /**
- * Whether the value in the BCD comes from the double fast path without having been rounded to
- * ensure correctness
- */
- UBool isApproximate;
-
- /**
- * The original number provided by the user and which is represented in BCD. Used when we need to
- * re-compute the BCD for an exact double representation.
- */
- double origDouble;
-
- /**
- * The change in magnitude relative to the original double. Used when we need to re-compute the
- * BCD for an exact double representation.
- */
- int32_t origDelta;
-
- // Positions to keep track of leading and trailing zeros.
- // lReqPos is the magnitude of the first required leading zero.
- // rReqPos is the magnitude of the last required trailing zero.
- int32_t lReqPos = 0;
- int32_t rReqPos = 0;
-
- // The value of the (suppressed) exponent after the number has been put into
- // a notation with exponents (ex: compact, scientific).
- int32_t exponent = 0;
-
- /**
- * The BCD of the 16 digits of the number represented by this object. Every 4 bits of the long map
- * to one digit. For example, the number "12345" in BCD is "0x12345".
- *
- * <p>Whenever bcd changes internally, {@link #compact()} must be called, except in special cases
- * like setting the digit to zero.
- */
- union {
- struct {
- int8_t *ptr;
- int32_t len;
- } bcdBytes;
- uint64_t bcdLong;
- } fBCD;
-
- bool usingBytes = false;
-
- /**
- * Whether this {@link DecimalQuantity} has been explicitly converted to an exact double. true if
- * backed by a double that was explicitly converted via convertToAccurateDouble; false otherwise.
- * Used for testing.
- */
- bool explicitExactDouble = false;
-
- void roundToMagnitude(int32_t magnitude, RoundingMode roundingMode, bool nickel, UErrorCode& status);
-
- /**
- * Returns a single digit from the BCD list. No internal state is changed by calling this method.
- *
- * @param position The position of the digit to pop, counted in BCD units from the least
- * significant digit. If outside the range supported by the implementation, zero is returned.
- * @return The digit at the specified location.
- */
- int8_t getDigitPos(int32_t position) const;
-
- /**
- * Sets the digit in the BCD list. This method only sets the digit; it is the caller's
- * responsibility to call {@link #compact} after setting the digit.
- *
- * @param position The position of the digit to pop, counted in BCD units from the least
- * significant digit. If outside the range supported by the implementation, an AssertionError
- * is thrown.
- * @param value The digit to set at the specified location.
- */
- void setDigitPos(int32_t position, int8_t value);
-
- /**
- * Adds zeros to the end of the BCD list. This will result in an invalid BCD representation; it is
- * the caller's responsibility to do further manipulation and then call {@link #compact}.
- *
- * @param numDigits The number of zeros to add.
- */
- void shiftLeft(int32_t numDigits);
-
- /**
- * Directly removes digits from the end of the BCD list.
- * Updates the scale and precision.
- *
- * CAUTION: it is the caller's responsibility to call {@link #compact} after this method.
- */
- void shiftRight(int32_t numDigits);
-
- /**
- * Directly removes digits from the front of the BCD list.
- * Updates precision.
- *
- * CAUTION: it is the caller's responsibility to call {@link #compact} after this method.
- */
- void popFromLeft(int32_t numDigits);
-
- /**
- * Sets the internal representation to zero. Clears any values stored in scale, precision,
- * hasDouble, origDouble, origDelta, exponent, and BCD data.
- */
- void setBcdToZero();
-
- /**
- * Sets the internal BCD state to represent the value in the given int. The int is guaranteed to
- * be either positive. The internal state is guaranteed to be empty when this method is called.
- *
- * @param n The value to consume.
- */
- void readIntToBcd(int32_t n);
-
- /**
- * Sets the internal BCD state to represent the value in the given long. The long is guaranteed to
- * be either positive. The internal state is guaranteed to be empty when this method is called.
- *
- * @param n The value to consume.
- */
- void readLongToBcd(int64_t n);
-
- 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
- * digit.
- *
- * <p>This method must always be called when bcd changes in order for assumptions to be correct in
- * methods like {@link #fractionCount()}.
- */
- void compact();
-
- void _setToInt(int32_t n);
-
- void _setToLong(int64_t n);
-
- void _setToDoubleFast(double n);
-
- void _setToDecNum(const DecNum& dn, UErrorCode& status);
-
- void convertToAccurateDouble();
-
- /** Ensure that a byte array of at least 40 digits is allocated. */
- void ensureCapacity();
-
- void ensureCapacity(int32_t capacity);
-
- /** Switches the internal storage mechanism between the 64-bit long and the byte array. */
- void switchStorage();
-};
-
-} // namespace impl
-} // namespace number
-U_NAMESPACE_END
-
-
-#endif //__NUMBER_DECIMALQUANTITY_H__
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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_DECIMALQUANTITY_H__
+#define __NUMBER_DECIMALQUANTITY_H__
+
+#include <cstdint>
+#include "unicode/umachine.h"
+#include "standardplural.h"
+#include "plurrule_impl.h"
+#include "number_types.h"
+
+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.
+ *
+ * <p>By design, this is NOT IMMUTABLE and NOT THREAD SAFE. It is intended to be an intermediate
+ * object holding state during a pass through the decimal formatting pipeline.
+ *
+ * <p>Represents numbers and digit display properties using Binary Coded Decimal (BCD).
+ *
+ * <p>Java has multiple implementations for testing, but C++ has only one implementation.
+ */
+class U_I18N_API DecimalQuantity : public IFixedDecimal, public UMemory {
+ public:
+ /** Copy constructor. */
+ DecimalQuantity(const DecimalQuantity &other);
+
+ /** Move constructor. */
+ DecimalQuantity(DecimalQuantity &&src) U_NOEXCEPT;
+
+ DecimalQuantity();
+
+ ~DecimalQuantity() override;
+
+ /**
+ * Sets this instance to be equal to another instance.
+ *
+ * @param other The instance to copy from.
+ */
+ DecimalQuantity &operator=(const DecimalQuantity &other);
+
+ /** Move assignment */
+ DecimalQuantity &operator=(DecimalQuantity&& src) U_NOEXCEPT;
+
+ /**
+ * Sets the minimum integer digits that this {@link DecimalQuantity} should generate.
+ * This method does not perform rounding.
+ *
+ * @param minInt The minimum number of integer digits.
+ */
+ void setMinInteger(int32_t minInt);
+
+ /**
+ * Sets the minimum fraction digits that this {@link DecimalQuantity} should generate.
+ * This method does not perform rounding.
+ *
+ * @param minFrac The minimum number of fraction digits.
+ */
+ void setMinFraction(int32_t minFrac);
+
+ /**
+ * Truncates digits from the upper magnitude of the number in order to satisfy the
+ * specified maximum number of integer digits.
+ *
+ * @param maxInt The maximum number of integer digits.
+ */
+ void applyMaxInteger(int32_t maxInt);
+
+ /**
+ * Rounds the number to a specified interval, such as 0.05.
+ *
+ * <p>If rounding to a power of ten, use the more efficient {@link #roundToMagnitude} instead.
+ *
+ * @param roundingIncrement The increment to which to round.
+ * @param roundingMode The {@link RoundingMode} to use if rounding is necessary.
+ */
+ void roundToIncrement(double roundingIncrement, RoundingMode roundingMode,
+ UErrorCode& status);
+
+ /** Removes all fraction digits. */
+ void truncate();
+
+ /**
+ * Rounds the number to the nearest multiple of 5 at the specified magnitude.
+ * For example, when magnitude == -2, this performs rounding to the nearest 0.05.
+ *
+ * @param magnitude The magnitude at which the digit should become either 0 or 5.
+ * @param roundingMode Rounding strategy.
+ */
+ void roundToNickel(int32_t magnitude, RoundingMode roundingMode, UErrorCode& status);
+
+ /**
+ * Rounds the number to a specified magnitude (power of ten).
+ *
+ * @param roundingMagnitude The power of ten to which to round. For example, a value of -2 will
+ * round to 2 decimal places.
+ * @param roundingMode The {@link RoundingMode} to use if rounding is necessary.
+ */
+ void roundToMagnitude(int32_t magnitude, RoundingMode roundingMode, UErrorCode& status);
+
+ /**
+ * Rounds the number to an infinite number of decimal points. This has no effect except for
+ * forcing the double in {@link DecimalQuantity_AbstractBCD} to adopt its exact representation.
+ */
+ void roundToInfinity();
+
+ /**
+ * 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 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.
+ */
+ bool adjustMagnitude(int32_t delta);
+
+ /**
+ * @return The power of ten corresponding to the most significant nonzero digit.
+ * The number must not be zero.
+ */
+ int32_t getMagnitude() const;
+
+ /**
+ * @return The value of the (suppressed) exponent after the number has been
+ * put into a notation with exponents (ex: compact, scientific). Ex: given
+ * the number 1000 as "1K" / "1E3", the return value will be 3 (positive).
+ */
+ int32_t getExponent() const;
+
+ /**
+ * Adjusts the value for the (suppressed) exponent stored when using
+ * notation with exponents (ex: compact, scientific).
+ *
+ * <p>Adjusting the exponent is decoupled from {@link #adjustMagnitude} in
+ * order to allow flexibility for {@link StandardPlural} to be selected in
+ * formatting (ex: for compact notation) either with or without the exponent
+ * applied in the value of the number.
+ * @param delta
+ * The value to adjust the exponent by.
+ */
+ void adjustExponent(int32_t delta);
+
+ /**
+ * @return Whether the value represented by this {@link DecimalQuantity} is
+ * zero, infinity, or NaN.
+ */
+ bool isZeroish() const;
+
+ /** @return Whether the value represented by this {@link DecimalQuantity} is less than zero. */
+ bool isNegative() const;
+
+ /** @return The appropriate value from the Signum enum. */
+ Signum signum() const;
+
+ /** @return Whether the value represented by this {@link DecimalQuantity} is infinite. */
+ bool isInfinite() const U_OVERRIDE;
+
+ /** @return Whether the value represented by this {@link DecimalQuantity} is not a number. */
+ bool isNaN() const U_OVERRIDE;
+
+ /**
+ * Note: this method incorporates the value of {@code exponent}
+ * (for cases such as compact notation) to return the proper long value
+ * represented by the result.
+ * @param truncateIfOverflow if false and the number does NOT fit, fails with an assertion error.
+ */
+ int64_t toLong(bool truncateIfOverflow = false) const;
+
+ /**
+ * Note: this method incorporates the value of {@code exponent}
+ * (for cases such as compact notation) to return the proper long value
+ * represented by the result.
+ */
+ 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);
+
+ DecimalQuantity &setToDouble(double n);
+
+ /** decNumber is similar to BigDecimal in Java. */
+ DecimalQuantity &setToDecNumber(StringPiece n, UErrorCode& status);
+
+ /** 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
+ * by this DecimalQuantity.
+ *
+ * <p>The primary use of this method is to construct numbers during a parsing loop. It allows
+ * parsing to take advantage of the digit list infrastructure primarily designed for formatting.
+ *
+ * @param value The digit to append.
+ * @param leadingZeros The number of zeros to append before the digit. For example, if the value
+ * in this instance starts as 12.3, and you append a 4 with 1 leading zero, the value becomes
+ * 12.304.
+ * @param appendAsInteger If true, increase the magnitude of existing digits to make room for the
+ * new digit. If false, append to the end like a fraction digit. If true, there must not be
+ * any fraction digits already in the number.
+ * @internal
+ * @deprecated This API is ICU internal only.
+ */
+ void appendDigit(int8_t value, int32_t leadingZeros, bool appendAsInteger);
+
+ 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.
+ *
+ * @param magnitude The magnitude of the digit.
+ * @return The digit at the specified magnitude.
+ */
+ int8_t getDigit(int32_t magnitude) const;
+
+ /**
+ * Gets the largest power of ten that needs to be displayed. The value returned by this function
+ * will be bounded between minInt and maxInt.
+ *
+ * @return The highest-magnitude digit to be displayed.
+ */
+ int32_t getUpperDisplayMagnitude() const;
+
+ /**
+ * Gets the smallest power of ten that needs to be displayed. The value returned by this function
+ * will be bounded between -minFrac and -maxFrac.
+ *
+ * @return The lowest-magnitude digit to be displayed.
+ */
+ int32_t getLowerDisplayMagnitude() const;
+
+ int32_t fractionCount() const;
+
+ int32_t fractionCountWithoutTrailingZeros() const;
+
+ void clear();
+
+ /** This method is for internal testing only. */
+ uint64_t getPositionFingerprint() const;
+
+// /**
+// * If the given {@link FieldPosition} is a {@link UFieldPosition}, populates it with the fraction
+// * length and fraction long value. If the argument is not a {@link UFieldPosition}, nothing
+// * happens.
+// *
+// * @param fp The {@link UFieldPosition} to populate.
+// */
+// void populateUFieldPosition(FieldPosition fp);
+
+ /**
+ * Checks whether the bytes stored in this instance are all valid. For internal unit testing only.
+ *
+ * @return An error message if this instance is invalid, or null if this instance is healthy.
+ */
+ const char16_t* checkHealth() const;
+
+ UnicodeString toString() const;
+
+ /** Returns the string in standard exponential notation. */
+ UnicodeString toScientificString() const;
+
+ /** Returns the string without exponential notation. Slightly slower than toScientificString(). */
+ UnicodeString toPlainString() const;
+
+ /** Visible for testing */
+ inline bool isUsingBytes() { return usingBytes; }
+
+ /** 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
+ * object represents the number "3.14", the BCD will be "0x314" and the scale will be -2.
+ *
+ * <p>Note that in {@link java.math.BigDecimal}, the scale is defined differently: the number of
+ * digits after the decimal place, which is the negative of our definition of scale.
+ */
+ int32_t scale;
+
+ /**
+ * The number of digits in the BCD. For example, "1007" has BCD "0x1007" and precision 4. The
+ * maximum precision is 16 since a long can hold only 16 digits.
+ *
+ * <p>This value must be re-calculated whenever the value in bcd changes by using {@link
+ * #computePrecisionAndCompact()}.
+ */
+ int32_t precision;
+
+ /**
+ * A bitmask of properties relating to the number represented by this object.
+ *
+ * @see #NEGATIVE_FLAG
+ * @see #INFINITY_FLAG
+ * @see #NAN_FLAG
+ */
+ int8_t flags;
+
+ // The following three fields relate to the double-to-ascii fast path algorithm.
+ // When a double is given to DecimalQuantityBCD, it is converted to using a fast algorithm. The
+ // fast algorithm guarantees correctness to only the first ~12 digits of the double. The process
+ // of rounding the number ensures that the converted digits are correct, falling back to a slow-
+ // path algorithm if required. Therefore, if a DecimalQuantity is constructed from a double, it
+ // is *required* that roundToMagnitude(), roundToIncrement(), or roundToInfinity() is called. If
+ // you don't round, assertions will fail in certain other methods if you try calling them.
+
+ /**
+ * Whether the value in the BCD comes from the double fast path without having been rounded to
+ * ensure correctness
+ */
+ UBool isApproximate;
+
+ /**
+ * The original number provided by the user and which is represented in BCD. Used when we need to
+ * re-compute the BCD for an exact double representation.
+ */
+ double origDouble;
+
+ /**
+ * The change in magnitude relative to the original double. Used when we need to re-compute the
+ * BCD for an exact double representation.
+ */
+ int32_t origDelta;
+
+ // Positions to keep track of leading and trailing zeros.
+ // lReqPos is the magnitude of the first required leading zero.
+ // rReqPos is the magnitude of the last required trailing zero.
+ int32_t lReqPos = 0;
+ int32_t rReqPos = 0;
+
+ // The value of the (suppressed) exponent after the number has been put into
+ // a notation with exponents (ex: compact, scientific).
+ int32_t exponent = 0;
+
+ /**
+ * The BCD of the 16 digits of the number represented by this object. Every 4 bits of the long map
+ * to one digit. For example, the number "12345" in BCD is "0x12345".
+ *
+ * <p>Whenever bcd changes internally, {@link #compact()} must be called, except in special cases
+ * like setting the digit to zero.
+ */
+ union {
+ struct {
+ int8_t *ptr;
+ int32_t len;
+ } bcdBytes;
+ uint64_t bcdLong;
+ } fBCD;
+
+ bool usingBytes = false;
+
+ /**
+ * Whether this {@link DecimalQuantity} has been explicitly converted to an exact double. true if
+ * backed by a double that was explicitly converted via convertToAccurateDouble; false otherwise.
+ * Used for testing.
+ */
+ bool explicitExactDouble = false;
+
+ void roundToMagnitude(int32_t magnitude, RoundingMode roundingMode, bool nickel, UErrorCode& status);
+
+ /**
+ * Returns a single digit from the BCD list. No internal state is changed by calling this method.
+ *
+ * @param position The position of the digit to pop, counted in BCD units from the least
+ * significant digit. If outside the range supported by the implementation, zero is returned.
+ * @return The digit at the specified location.
+ */
+ int8_t getDigitPos(int32_t position) const;
+
+ /**
+ * Sets the digit in the BCD list. This method only sets the digit; it is the caller's
+ * responsibility to call {@link #compact} after setting the digit.
+ *
+ * @param position The position of the digit to pop, counted in BCD units from the least
+ * significant digit. If outside the range supported by the implementation, an AssertionError
+ * is thrown.
+ * @param value The digit to set at the specified location.
+ */
+ void setDigitPos(int32_t position, int8_t value);
+
+ /**
+ * Adds zeros to the end of the BCD list. This will result in an invalid BCD representation; it is
+ * the caller's responsibility to do further manipulation and then call {@link #compact}.
+ *
+ * @param numDigits The number of zeros to add.
+ */
+ void shiftLeft(int32_t numDigits);
+
+ /**
+ * Directly removes digits from the end of the BCD list.
+ * Updates the scale and precision.
+ *
+ * CAUTION: it is the caller's responsibility to call {@link #compact} after this method.
+ */
+ void shiftRight(int32_t numDigits);
+
+ /**
+ * Directly removes digits from the front of the BCD list.
+ * Updates precision.
+ *
+ * CAUTION: it is the caller's responsibility to call {@link #compact} after this method.
+ */
+ void popFromLeft(int32_t numDigits);
+
+ /**
+ * Sets the internal representation to zero. Clears any values stored in scale, precision,
+ * hasDouble, origDouble, origDelta, exponent, and BCD data.
+ */
+ void setBcdToZero();
+
+ /**
+ * Sets the internal BCD state to represent the value in the given int. The int is guaranteed to
+ * be either positive. The internal state is guaranteed to be empty when this method is called.
+ *
+ * @param n The value to consume.
+ */
+ void readIntToBcd(int32_t n);
+
+ /**
+ * Sets the internal BCD state to represent the value in the given long. The long is guaranteed to
+ * be either positive. The internal state is guaranteed to be empty when this method is called.
+ *
+ * @param n The value to consume.
+ */
+ void readLongToBcd(int64_t n);
+
+ 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
+ * digit.
+ *
+ * <p>This method must always be called when bcd changes in order for assumptions to be correct in
+ * methods like {@link #fractionCount()}.
+ */
+ void compact();
+
+ void _setToInt(int32_t n);
+
+ void _setToLong(int64_t n);
+
+ void _setToDoubleFast(double n);
+
+ void _setToDecNum(const DecNum& dn, UErrorCode& status);
+
+ void convertToAccurateDouble();
+
+ /** Ensure that a byte array of at least 40 digits is allocated. */
+ void ensureCapacity();
+
+ void ensureCapacity(int32_t capacity);
+
+ /** Switches the internal storage mechanism between the 64-bit long and the byte array. */
+ void switchStorage();
+};
+
+} // namespace impl
+} // namespace number
+U_NAMESPACE_END
+
+
+#endif //__NUMBER_DECIMALQUANTITY_H__
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_decimfmtprops.cpp b/contrib/libs/icu/i18n/number_decimfmtprops.cpp
index 30481ce5bf..b569e59178 100644
--- a/contrib/libs/icu/i18n/number_decimfmtprops.cpp
+++ b/contrib/libs/icu/i18n/number_decimfmtprops.cpp
@@ -1,152 +1,152 @@
-// © 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
-
-#include "number_decimfmtprops.h"
-#include "umutex.h"
-
-using namespace icu;
-using namespace icu::number;
-using namespace icu::number::impl;
-
-
-namespace {
-
-alignas(DecimalFormatProperties)
-char kRawDefaultProperties[sizeof(DecimalFormatProperties)];
-
-icu::UInitOnce gDefaultPropertiesInitOnce = U_INITONCE_INITIALIZER;
-
-void U_CALLCONV initDefaultProperties(UErrorCode&) {
- // can't fail, uses placement new into staticly allocated space.
- new(kRawDefaultProperties) DecimalFormatProperties(); // set to the default instance
-}
-
-}
-
-
-DecimalFormatProperties::DecimalFormatProperties() {
- clear();
-}
-
-void DecimalFormatProperties::clear() {
- compactStyle.nullify();
- currency.nullify();
- currencyPluralInfo.fPtr.adoptInstead(nullptr);
- currencyUsage.nullify();
- decimalPatternMatchRequired = false;
- decimalSeparatorAlwaysShown = false;
- exponentSignAlwaysShown = false;
- formatFailIfMoreThanMaxDigits = false;
- formatWidth = -1;
- groupingSize = -1;
- groupingUsed = true;
- magnitudeMultiplier = 0;
- maximumFractionDigits = -1;
- maximumIntegerDigits = -1;
- maximumSignificantDigits = -1;
- minimumExponentDigits = -1;
- minimumFractionDigits = -1;
- minimumGroupingDigits = -1;
- minimumIntegerDigits = -1;
- minimumSignificantDigits = -1;
- multiplier = 1;
- multiplierScale = 0;
- negativePrefix.setToBogus();
- negativePrefixPattern.setToBogus();
- negativeSuffix.setToBogus();
- negativeSuffixPattern.setToBogus();
- padPosition.nullify();
- padString.setToBogus();
- parseCaseSensitive = false;
- parseIntegerOnly = false;
- parseMode.nullify();
- parseNoExponent = false;
- parseToBigDecimal = false;
- parseAllInput = UNUM_MAYBE;
- positivePrefix.setToBogus();
- positivePrefixPattern.setToBogus();
- positiveSuffix.setToBogus();
- positiveSuffixPattern.setToBogus();
- roundingIncrement = 0.0;
- roundingMode.nullify();
- secondaryGroupingSize = -1;
- signAlwaysShown = false;
-}
-
-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 && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown;
- eq = eq && exponentSignAlwaysShown == other.exponentSignAlwaysShown;
- eq = eq && formatFailIfMoreThanMaxDigits == other.formatFailIfMoreThanMaxDigits;
- eq = eq && formatWidth == other.formatWidth;
- eq = eq && magnitudeMultiplier == other.magnitudeMultiplier;
- eq = eq && maximumSignificantDigits == other.maximumSignificantDigits;
- eq = eq && minimumExponentDigits == other.minimumExponentDigits;
- eq = eq && minimumGroupingDigits == other.minimumGroupingDigits;
- eq = eq && minimumSignificantDigits == other.minimumSignificantDigits;
- eq = eq && multiplier == other.multiplier;
- eq = eq && multiplierScale == other.multiplierScale;
- eq = eq && negativePrefix == other.negativePrefix;
- eq = eq && negativeSuffix == other.negativeSuffix;
- eq = eq && padPosition == other.padPosition;
- eq = eq && padString == other.padString;
- eq = eq && positivePrefix == other.positivePrefix;
- eq = eq && positiveSuffix == other.positiveSuffix;
- 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<DecimalFormatProperties*>(kRawDefaultProperties), true);
-}
-
-const DecimalFormatProperties& DecimalFormatProperties::getDefault() {
- UErrorCode localStatus = U_ZERO_ERROR;
- umtx_initOnce(gDefaultPropertiesInitOnce, &initDefaultProperties, localStatus);
- return *reinterpret_cast<const DecimalFormatProperties*>(kRawDefaultProperties);
-}
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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
+
+#include "number_decimfmtprops.h"
+#include "umutex.h"
+
+using namespace icu;
+using namespace icu::number;
+using namespace icu::number::impl;
+
+
+namespace {
+
+alignas(DecimalFormatProperties)
+char kRawDefaultProperties[sizeof(DecimalFormatProperties)];
+
+icu::UInitOnce gDefaultPropertiesInitOnce = U_INITONCE_INITIALIZER;
+
+void U_CALLCONV initDefaultProperties(UErrorCode&) {
+ // can't fail, uses placement new into staticly allocated space.
+ new(kRawDefaultProperties) DecimalFormatProperties(); // set to the default instance
+}
+
+}
+
+
+DecimalFormatProperties::DecimalFormatProperties() {
+ clear();
+}
+
+void DecimalFormatProperties::clear() {
+ compactStyle.nullify();
+ currency.nullify();
+ currencyPluralInfo.fPtr.adoptInstead(nullptr);
+ currencyUsage.nullify();
+ decimalPatternMatchRequired = false;
+ decimalSeparatorAlwaysShown = false;
+ exponentSignAlwaysShown = false;
+ formatFailIfMoreThanMaxDigits = false;
+ formatWidth = -1;
+ groupingSize = -1;
+ groupingUsed = true;
+ magnitudeMultiplier = 0;
+ maximumFractionDigits = -1;
+ maximumIntegerDigits = -1;
+ maximumSignificantDigits = -1;
+ minimumExponentDigits = -1;
+ minimumFractionDigits = -1;
+ minimumGroupingDigits = -1;
+ minimumIntegerDigits = -1;
+ minimumSignificantDigits = -1;
+ multiplier = 1;
+ multiplierScale = 0;
+ negativePrefix.setToBogus();
+ negativePrefixPattern.setToBogus();
+ negativeSuffix.setToBogus();
+ negativeSuffixPattern.setToBogus();
+ padPosition.nullify();
+ padString.setToBogus();
+ parseCaseSensitive = false;
+ parseIntegerOnly = false;
+ parseMode.nullify();
+ parseNoExponent = false;
+ parseToBigDecimal = false;
+ parseAllInput = UNUM_MAYBE;
+ positivePrefix.setToBogus();
+ positivePrefixPattern.setToBogus();
+ positiveSuffix.setToBogus();
+ positiveSuffixPattern.setToBogus();
+ roundingIncrement = 0.0;
+ roundingMode.nullify();
+ secondaryGroupingSize = -1;
+ signAlwaysShown = false;
+}
+
+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 && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown;
+ eq = eq && exponentSignAlwaysShown == other.exponentSignAlwaysShown;
+ eq = eq && formatFailIfMoreThanMaxDigits == other.formatFailIfMoreThanMaxDigits;
+ eq = eq && formatWidth == other.formatWidth;
+ eq = eq && magnitudeMultiplier == other.magnitudeMultiplier;
+ eq = eq && maximumSignificantDigits == other.maximumSignificantDigits;
+ eq = eq && minimumExponentDigits == other.minimumExponentDigits;
+ eq = eq && minimumGroupingDigits == other.minimumGroupingDigits;
+ eq = eq && minimumSignificantDigits == other.minimumSignificantDigits;
+ eq = eq && multiplier == other.multiplier;
+ eq = eq && multiplierScale == other.multiplierScale;
+ eq = eq && negativePrefix == other.negativePrefix;
+ eq = eq && negativeSuffix == other.negativeSuffix;
+ eq = eq && padPosition == other.padPosition;
+ eq = eq && padString == other.padString;
+ eq = eq && positivePrefix == other.positivePrefix;
+ eq = eq && positiveSuffix == other.positiveSuffix;
+ 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<DecimalFormatProperties*>(kRawDefaultProperties), true);
+}
+
+const DecimalFormatProperties& DecimalFormatProperties::getDefault() {
+ UErrorCode localStatus = U_ZERO_ERROR;
+ umtx_initOnce(gDefaultPropertiesInitOnce, &initDefaultProperties, localStatus);
+ return *reinterpret_cast<const DecimalFormatProperties*>(kRawDefaultProperties);
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_decimfmtprops.h b/contrib/libs/icu/i18n/number_decimfmtprops.h
index 1ce84d9dc3..c32f7f3dc9 100644
--- a/contrib/libs/icu/i18n/number_decimfmtprops.h
+++ b/contrib/libs/icu/i18n/number_decimfmtprops.h
@@ -1,174 +1,174 @@
-// © 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_DECIMFMTPROPS_H__
-#define __NUMBER_DECIMFMTPROPS_H__
-
-#include "unicode/unistr.h"
-#include <cstdint>
-#include "unicode/plurrule.h"
-#include "unicode/currpinf.h"
-#include "unicode/unum.h"
-#include "unicode/localpointer.h"
-#include "number_types.h"
-
-U_NAMESPACE_BEGIN
-
-// Export an explicit template instantiation of the LocalPointer that is used as a
-// data member of CurrencyPluralInfoWrapper.
-// (When building DLLs for Windows this is required.)
-#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
-#if defined(_MSC_VER)
-// Ignore warning 4661 as LocalPointerBase does not use operator== or operator!=
-#pragma warning(push)
-#pragma warning(disable: 4661)
-#endif
-template class U_I18N_API LocalPointerBase<CurrencyPluralInfo>;
-template class U_I18N_API LocalPointer<CurrencyPluralInfo>;
-#if defined(_MSC_VER)
-#pragma warning(pop)
-#endif
-#endif
-
-namespace number {
-namespace impl {
-
-// Exported as U_I18N_API because it is a public member field of exported DecimalFormatProperties
-// 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<CurrencyPluralInfo> fPtr;
-
- 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:
- *
- * <ul>
- * <li>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".
- * <li>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.)
- * <li>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.
- * <li>Leading grouping separators are not allowed, as in ",123".
- * <li>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.
- * <li>The set of characters that can be interpreted as a decimal or grouping separator is
- * smaller.
- * <li><strong>If currency parsing is enabled,</strong> 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.
- * </ul>
- */
- PARSE_MODE_STRICT,
-};
-
-// Exported as U_I18N_API because it is needed for the unit test PatternStringTest
-struct U_I18N_API DecimalFormatProperties : public UMemory {
-
- public:
- NullableValue<UNumberCompactStyle> compactStyle;
- NullableValue<CurrencyUnit> currency;
- CurrencyPluralInfoWrapper currencyPluralInfo;
- NullableValue<UCurrencyUsage> currencyUsage;
- bool decimalPatternMatchRequired;
- bool decimalSeparatorAlwaysShown;
- bool exponentSignAlwaysShown;
- bool formatFailIfMoreThanMaxDigits; // ICU4C-only
- int32_t formatWidth;
- int32_t groupingSize;
- bool groupingUsed;
- int32_t magnitudeMultiplier; // internal field like multiplierScale but separate to avoid conflict
- int32_t maximumFractionDigits;
- int32_t maximumIntegerDigits;
- int32_t maximumSignificantDigits;
- int32_t minimumExponentDigits;
- int32_t minimumFractionDigits;
- int32_t minimumGroupingDigits;
- int32_t minimumIntegerDigits;
- int32_t minimumSignificantDigits;
- int32_t multiplier;
- int32_t multiplierScale; // ICU4C-only
- UnicodeString negativePrefix;
- UnicodeString negativePrefixPattern;
- UnicodeString negativeSuffix;
- UnicodeString negativeSuffixPattern;
- NullableValue<PadPosition> padPosition;
- UnicodeString padString;
- bool parseCaseSensitive;
- bool parseIntegerOnly;
- NullableValue<ParseMode> parseMode;
- bool parseNoExponent;
- bool parseToBigDecimal; // TODO: Not needed in ICU4C?
- UNumberFormatAttributeValue parseAllInput; // ICU4C-only
- //PluralRules pluralRules;
- UnicodeString positivePrefix;
- UnicodeString positivePrefixPattern;
- UnicodeString positiveSuffix;
- UnicodeString positiveSuffixPattern;
- double roundingIncrement;
- NullableValue<RoundingMode> roundingMode;
- int32_t secondaryGroupingSize;
- bool signAlwaysShown;
-
- DecimalFormatProperties();
-
- inline bool operator==(const DecimalFormatProperties& other) const {
- return _equals(other, false);
- }
-
- void clear();
-
- /**
- * Checks for equality to the default DecimalFormatProperties, but ignores the prescribed set of
- * options for fast-path formatting.
- */
- bool equalsDefaultExceptFastFormat() const;
-
- /**
- * Returns the default DecimalFormatProperties instance.
- */
- static const DecimalFormatProperties& getDefault();
-
- private:
- bool _equals(const DecimalFormatProperties& other, bool ignoreForFastFormat) const;
-};
-
-} // namespace impl
-} // namespace number
-U_NAMESPACE_END
-
-
-#endif //__NUMBER_DECIMFMTPROPS_H__
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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_DECIMFMTPROPS_H__
+#define __NUMBER_DECIMFMTPROPS_H__
+
+#include "unicode/unistr.h"
+#include <cstdint>
+#include "unicode/plurrule.h"
+#include "unicode/currpinf.h"
+#include "unicode/unum.h"
+#include "unicode/localpointer.h"
+#include "number_types.h"
+
+U_NAMESPACE_BEGIN
+
+// Export an explicit template instantiation of the LocalPointer that is used as a
+// data member of CurrencyPluralInfoWrapper.
+// (When building DLLs for Windows this is required.)
+#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
+#if defined(_MSC_VER)
+// Ignore warning 4661 as LocalPointerBase does not use operator== or operator!=
+#pragma warning(push)
+#pragma warning(disable: 4661)
+#endif
+template class U_I18N_API LocalPointerBase<CurrencyPluralInfo>;
+template class U_I18N_API LocalPointer<CurrencyPluralInfo>;
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+#endif
+
+namespace number {
+namespace impl {
+
+// Exported as U_I18N_API because it is a public member field of exported DecimalFormatProperties
+// 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<CurrencyPluralInfo> fPtr;
+
+ 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:
+ *
+ * <ul>
+ * <li>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".
+ * <li>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.)
+ * <li>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.
+ * <li>Leading grouping separators are not allowed, as in ",123".
+ * <li>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.
+ * <li>The set of characters that can be interpreted as a decimal or grouping separator is
+ * smaller.
+ * <li><strong>If currency parsing is enabled,</strong> 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.
+ * </ul>
+ */
+ PARSE_MODE_STRICT,
+};
+
+// Exported as U_I18N_API because it is needed for the unit test PatternStringTest
+struct U_I18N_API DecimalFormatProperties : public UMemory {
+
+ public:
+ NullableValue<UNumberCompactStyle> compactStyle;
+ NullableValue<CurrencyUnit> currency;
+ CurrencyPluralInfoWrapper currencyPluralInfo;
+ NullableValue<UCurrencyUsage> currencyUsage;
+ bool decimalPatternMatchRequired;
+ bool decimalSeparatorAlwaysShown;
+ bool exponentSignAlwaysShown;
+ bool formatFailIfMoreThanMaxDigits; // ICU4C-only
+ int32_t formatWidth;
+ int32_t groupingSize;
+ bool groupingUsed;
+ int32_t magnitudeMultiplier; // internal field like multiplierScale but separate to avoid conflict
+ int32_t maximumFractionDigits;
+ int32_t maximumIntegerDigits;
+ int32_t maximumSignificantDigits;
+ int32_t minimumExponentDigits;
+ int32_t minimumFractionDigits;
+ int32_t minimumGroupingDigits;
+ int32_t minimumIntegerDigits;
+ int32_t minimumSignificantDigits;
+ int32_t multiplier;
+ int32_t multiplierScale; // ICU4C-only
+ UnicodeString negativePrefix;
+ UnicodeString negativePrefixPattern;
+ UnicodeString negativeSuffix;
+ UnicodeString negativeSuffixPattern;
+ NullableValue<PadPosition> padPosition;
+ UnicodeString padString;
+ bool parseCaseSensitive;
+ bool parseIntegerOnly;
+ NullableValue<ParseMode> parseMode;
+ bool parseNoExponent;
+ bool parseToBigDecimal; // TODO: Not needed in ICU4C?
+ UNumberFormatAttributeValue parseAllInput; // ICU4C-only
+ //PluralRules pluralRules;
+ UnicodeString positivePrefix;
+ UnicodeString positivePrefixPattern;
+ UnicodeString positiveSuffix;
+ UnicodeString positiveSuffixPattern;
+ double roundingIncrement;
+ NullableValue<RoundingMode> roundingMode;
+ int32_t secondaryGroupingSize;
+ bool signAlwaysShown;
+
+ DecimalFormatProperties();
+
+ inline bool operator==(const DecimalFormatProperties& other) const {
+ return _equals(other, false);
+ }
+
+ void clear();
+
+ /**
+ * Checks for equality to the default DecimalFormatProperties, but ignores the prescribed set of
+ * options for fast-path formatting.
+ */
+ bool equalsDefaultExceptFastFormat() const;
+
+ /**
+ * Returns the default DecimalFormatProperties instance.
+ */
+ static const DecimalFormatProperties& getDefault();
+
+ private:
+ bool _equals(const DecimalFormatProperties& other, bool ignoreForFastFormat) const;
+};
+
+} // namespace impl
+} // namespace number
+U_NAMESPACE_END
+
+
+#endif //__NUMBER_DECIMFMTPROPS_H__
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_decnum.h b/contrib/libs/icu/i18n/number_decnum.h
index 0c7399dbdd..bf953d6194 100644
--- a/contrib/libs/icu/i18n/number_decnum.h
+++ b/contrib/libs/icu/i18n/number_decnum.h
@@ -1,79 +1,79 @@
-// © 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<decNumber, char, DECNUM_INITIAL_CAPACITY>;
-#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;
-
- void toString(ByteSink& output, UErrorCode& status) const;
-
- inline const decNumber* getRawDecNumber() const {
- return fData.getAlias();
- }
-
- private:
- static constexpr int32_t kDefaultDigits = DECNUM_INITIAL_CAPACITY;
- MaybeStackHeaderAndArray<decNumber, char, kDefaultDigits> 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 */
+// © 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<decNumber, char, DECNUM_INITIAL_CAPACITY>;
+#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;
+
+ void toString(ByteSink& output, UErrorCode& status) const;
+
+ inline const decNumber* getRawDecNumber() const {
+ return fData.getAlias();
+ }
+
+ private:
+ static constexpr int32_t kDefaultDigits = DECNUM_INITIAL_CAPACITY;
+ MaybeStackHeaderAndArray<decNumber, char, kDefaultDigits> 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/contrib/libs/icu/i18n/number_fluent.cpp b/contrib/libs/icu/i18n/number_fluent.cpp
index 9cdb8b7156..80f1f58a98 100644
--- a/contrib/libs/icu/i18n/number_fluent.cpp
+++ b/contrib/libs/icu/i18n/number_fluent.cpp
@@ -1,768 +1,768 @@
-// © 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
-
-#include "uassert.h"
-#include "unicode/numberformatter.h"
-#include "number_decimalquantity.h"
-#include "number_formatimpl.h"
-#include "umutex.h"
-#include "number_asformat.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;
-
-#if (U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN) && defined(_MSC_VER)
-// Ignore MSVC warning 4661. This is generated for NumberFormatterSettings<>::toSkeleton() as this method
-// is defined elsewhere (in number_skeletons.cpp). The compiler is warning that the explicit template instantiation
-// inside this single translation unit (CPP file) is incomplete, and thus it isn't sure if the template class is
-// fully defined. However, since each translation unit explicitly instantiates all the necessary template classes,
-// they will all be passed to the linker, and the linker will still find and export all the class members.
-#pragma warning(push)
-#pragma warning(disable: 4661)
-#endif
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::notation(const Notation& notation) const& {
- Derived copy(*this);
- // NOTE: Slicing is OK.
- copy.fMacros.notation = notation;
- return copy;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::notation(const Notation& notation)&& {
- Derived move(std::move(*this));
- // NOTE: Slicing is OK.
- move.fMacros.notation = notation;
- return move;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::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.
- copy.fMacros.unit = unit;
- return copy;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::unit(const icu::MeasureUnit& unit)&& {
- Derived move(std::move(*this));
- // See comments above about slicing.
- move.fMacros.unit = unit;
- return move;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::adoptUnit(icu::MeasureUnit* unit) const& {
- Derived copy(*this);
- // 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 = std::move(*unit);
- delete unit;
- }
- return copy;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::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<typename Derived>
-Derived NumberFormatterSettings<Derived>::perUnit(const icu::MeasureUnit& perUnit) const& {
- Derived copy(*this);
- // See comments above about slicing.
- copy.fMacros.perUnit = perUnit;
- return copy;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::perUnit(const icu::MeasureUnit& perUnit)&& {
- Derived move(std::move(*this));
- // See comments above about slicing.
- move.fMacros.perUnit = perUnit;
- return move;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::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 = std::move(*perUnit);
- delete perUnit;
- }
- return copy;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::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<typename Derived>
-Derived NumberFormatterSettings<Derived>::precision(const Precision& precision) const& {
- Derived copy(*this);
- // NOTE: Slicing is OK.
- copy.fMacros.precision = precision;
- return copy;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::precision(const Precision& precision)&& {
- Derived move(std::move(*this));
- // NOTE: Slicing is OK.
- move.fMacros.precision = precision;
- return move;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::roundingMode(UNumberFormatRoundingMode roundingMode) const& {
- Derived copy(*this);
- copy.fMacros.roundingMode = roundingMode;
- return copy;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::roundingMode(UNumberFormatRoundingMode roundingMode)&& {
- Derived move(std::move(*this));
- move.fMacros.roundingMode = roundingMode;
- return move;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::grouping(UNumberGroupingStrategy 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.
- copy.fMacros.grouper = Grouper::forStrategy(strategy);
- return copy;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::grouping(UNumberGroupingStrategy strategy)&& {
- Derived move(std::move(*this));
- move.fMacros.grouper = Grouper::forStrategy(strategy);
- return move;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::integerWidth(const IntegerWidth& style) const& {
- Derived copy(*this);
- copy.fMacros.integerWidth = style;
- return copy;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::integerWidth(const IntegerWidth& style)&& {
- Derived move(std::move(*this));
- move.fMacros.integerWidth = style;
- return move;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::symbols(const DecimalFormatSymbols& symbols) const& {
- Derived copy(*this);
- copy.fMacros.symbols.setTo(symbols);
- return copy;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::symbols(const DecimalFormatSymbols& symbols)&& {
- Derived move(std::move(*this));
- move.fMacros.symbols.setTo(symbols);
- return move;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::adoptSymbols(NumberingSystem* ns) const& {
- Derived copy(*this);
- copy.fMacros.symbols.setTo(ns);
- return copy;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::adoptSymbols(NumberingSystem* ns)&& {
- Derived move(std::move(*this));
- move.fMacros.symbols.setTo(ns);
- return move;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::unitWidth(UNumberUnitWidth width) const& {
- Derived copy(*this);
- copy.fMacros.unitWidth = width;
- return copy;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::unitWidth(UNumberUnitWidth width)&& {
- Derived move(std::move(*this));
- move.fMacros.unitWidth = width;
- return move;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::sign(UNumberSignDisplay style) const& {
- Derived copy(*this);
- copy.fMacros.sign = style;
- return copy;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::sign(UNumberSignDisplay style)&& {
- Derived move(std::move(*this));
- move.fMacros.sign = style;
- return move;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::decimal(UNumberDecimalSeparatorDisplay style) const& {
- Derived copy(*this);
- copy.fMacros.decimal = style;
- return copy;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::decimal(UNumberDecimalSeparatorDisplay style)&& {
- Derived move(std::move(*this));
- move.fMacros.decimal = style;
- return move;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::scale(const Scale& scale) const& {
- Derived copy(*this);
- copy.fMacros.scale = scale;
- return copy;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::scale(const Scale& scale)&& {
- Derived move(std::move(*this));
- move.fMacros.scale = scale;
- return move;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::padding(const Padder& padder) const& {
- Derived copy(*this);
- copy.fMacros.padder = padder;
- return copy;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::padding(const Padder& padder)&& {
- Derived move(std::move(*this));
- move.fMacros.padder = padder;
- return move;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::threshold(int32_t threshold) const& {
- Derived copy(*this);
- copy.fMacros.threshold = threshold;
- return copy;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::threshold(int32_t threshold)&& {
- Derived move(std::move(*this));
- move.fMacros.threshold = threshold;
- return move;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::macros(const impl::MacroProps& macros) const& {
- Derived copy(*this);
- copy.fMacros = macros;
- return copy;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::macros(const impl::MacroProps& macros)&& {
- Derived move(std::move(*this));
- move.fMacros = macros;
- return move;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::macros(impl::MacroProps&& macros) const& {
- Derived copy(*this);
- copy.fMacros = std::move(macros);
- return copy;
-}
-
-template<typename Derived>
-Derived NumberFormatterSettings<Derived>::macros(impl::MacroProps&& macros)&& {
- Derived move(std::move(*this));
- move.fMacros = std::move(macros);
- return move;
-}
-
-// Note: toSkeleton defined in number_skeletons.cpp
-
-template<typename Derived>
-LocalPointer<Derived> NumberFormatterSettings<Derived>::clone() const & {
- return LocalPointer<Derived>(new Derived(*this));
-}
-
-template<typename Derived>
-LocalPointer<Derived> NumberFormatterSettings<Derived>::clone() && {
- return LocalPointer<Derived>(new Derived(std::move(*this)));
-}
-
-// Declare all classes that implement NumberFormatterSettings
-// See https://stackoverflow.com/a/495056/1407170
-template
-class icu::number::NumberFormatterSettings<icu::number::UnlocalizedNumberFormatter>;
-template
-class icu::number::NumberFormatterSettings<icu::number::LocalizedNumberFormatter>;
-
-
-UnlocalizedNumberFormatter NumberFormatter::with() {
- UnlocalizedNumberFormatter result;
- return result;
-}
-
-LocalizedNumberFormatter NumberFormatter::withLocale(const Locale& locale) {
- return with().locale(locale);
-}
-
-// Note: forSkeleton defined in number_skeletons.cpp
-
-
-template<typename T> using NFS = NumberFormatterSettings<T>;
-using LNF = LocalizedNumberFormatter;
-using UNF = UnlocalizedNumberFormatter;
-
-UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(const UNF& other)
- : UNF(static_cast<const NFS<UNF>&>(other)) {}
-
-UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(const NFS<UNF>& other)
- : NFS<UNF>(other) {
- // No additional fields to assign
-}
-
-// Make default copy constructor call the NumberFormatterSettings copy constructor.
-UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(UNF&& src) U_NOEXCEPT
- : UNF(static_cast<NFS<UNF>&&>(src)) {}
-
-UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(NFS<UNF>&& src) U_NOEXCEPT
- : NFS<UNF>(std::move(src)) {
- // No additional fields to assign
-}
-
-UnlocalizedNumberFormatter& UnlocalizedNumberFormatter::operator=(const UNF& other) {
- NFS<UNF>::operator=(static_cast<const NFS<UNF>&>(other));
- // No additional fields to assign
- return *this;
-}
-
-UnlocalizedNumberFormatter& UnlocalizedNumberFormatter::operator=(UNF&& src) U_NOEXCEPT {
- NFS<UNF>::operator=(static_cast<NFS<UNF>&&>(src));
- // No additional fields to assign
- return *this;
-}
-
-// Make default copy constructor call the NumberFormatterSettings copy constructor.
-LocalizedNumberFormatter::LocalizedNumberFormatter(const LNF& other)
- : LNF(static_cast<const NFS<LNF>&>(other)) {}
-
-LocalizedNumberFormatter::LocalizedNumberFormatter(const NFS<LNF>& other)
- : NFS<LNF>(other) {
- // No additional fields to assign (let call count and compiled formatter reset to defaults)
-}
-
-LocalizedNumberFormatter::LocalizedNumberFormatter(LocalizedNumberFormatter&& src) U_NOEXCEPT
- : LNF(static_cast<NFS<LNF>&&>(src)) {}
-
-LocalizedNumberFormatter::LocalizedNumberFormatter(NFS<LNF>&& src) U_NOEXCEPT
- : NFS<LNF>(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<LNF&&>(src).fCompiled != nullptr) {
- lnfMoveHelper(static_cast<LNF&&>(src));
- }
-}
-
-LocalizedNumberFormatter& LocalizedNumberFormatter::operator=(const LNF& other) {
- NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other));
- // Reset to default values.
- clear();
- return *this;
-}
-
-LocalizedNumberFormatter& LocalizedNumberFormatter::operator=(LNF&& src) U_NOEXCEPT {
- NFS<LNF>::operator=(static_cast<NFS<LNF>&&>(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<LNF&&>(src).fCompiled != nullptr) {
- // Formatter is compiled
- lnfMoveHelper(static_cast<LNF&&>(src));
- } else {
- clear();
- }
- return *this;
-}
-
-void LocalizedNumberFormatter::clear() {
- // Reset to default values.
- auto* callCount = reinterpret_cast<u_atomic_int32_t*>(fUnsafeCallCount);
- umtx_storeRelease(*callCount, 0);
- delete fCompiled;
- fCompiled = nullptr;
-}
-
-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<u_atomic_int32_t*>(fUnsafeCallCount);
- umtx_storeRelease(*callCount, INT32_MIN);
- delete fCompiled;
- fCompiled = src.fCompiled;
- // Reset the source object to leave it in a safe state.
- auto* srcCallCount = reinterpret_cast<u_atomic_int32_t*>(src.fUnsafeCallCount);
- umtx_storeRelease(*srcCallCount, 0);
- src.fCompiled = nullptr;
-}
-
-
-LocalizedNumberFormatter::~LocalizedNumberFormatter() {
- delete fCompiled;
-}
-
-LocalizedNumberFormatter::LocalizedNumberFormatter(const MacroProps& macros, const Locale& locale) {
- fMacros = macros;
- fMacros.locale = locale;
-}
-
-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);
-}
-
-LocalizedNumberFormatter UnlocalizedNumberFormatter::locale(const Locale& locale)&& {
- return LocalizedNumberFormatter(std::move(fMacros), locale);
-}
-
-SymbolsWrapper::SymbolsWrapper(const SymbolsWrapper& other) {
- doCopyFrom(other);
-}
-
-SymbolsWrapper::SymbolsWrapper(SymbolsWrapper&& src) U_NOEXCEPT {
- doMoveFrom(std::move(src));
-}
-
-SymbolsWrapper& SymbolsWrapper::operator=(const SymbolsWrapper& other) {
- if (this == &other) {
- return *this;
- }
- doCleanup();
- doCopyFrom(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) {
- doCleanup();
- fType = SYMPTR_DFS;
- fPtr.dfs = new DecimalFormatSymbols(dfs);
-}
-
-void SymbolsWrapper::setTo(const NumberingSystem* ns) {
- doCleanup();
- fType = SYMPTR_NS;
- fPtr.ns = ns;
-}
-
-void SymbolsWrapper::doCopyFrom(const SymbolsWrapper& other) {
- fType = other.fType;
- switch (fType) {
- case SYMPTR_NONE:
- // No action necessary
- break;
- case SYMPTR_DFS:
- // Memory allocation failures are exposed in copyErrorTo()
- if (other.fPtr.dfs != nullptr) {
- fPtr.dfs = new DecimalFormatSymbols(*other.fPtr.dfs);
- } else {
- fPtr.dfs = nullptr;
- }
- break;
- case SYMPTR_NS:
- // Memory allocation failures are exposed in copyErrorTo()
- if (other.fPtr.ns != nullptr) {
- fPtr.ns = new NumberingSystem(*other.fPtr.ns);
- } else {
- fPtr.ns = nullptr;
- }
- break;
- }
-}
-
-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:
- // No action necessary
- break;
- case SYMPTR_DFS:
- delete fPtr.dfs;
- break;
- case SYMPTR_NS:
- delete fPtr.ns;
- break;
- }
-}
-
-bool SymbolsWrapper::isDecimalFormatSymbols() const {
- return fType == SYMPTR_DFS;
-}
-
-bool SymbolsWrapper::isNumberingSystem() const {
- return fType == SYMPTR_NS;
-}
-
-const DecimalFormatSymbols* SymbolsWrapper::getDecimalFormatSymbols() const {
- U_ASSERT(fType == SYMPTR_DFS);
- return fPtr.dfs;
-}
-
-const NumberingSystem* SymbolsWrapper::getNumberingSystem() const {
- U_ASSERT(fType == SYMPTR_NS);
- return fPtr.ns;
-}
-
-
-FormattedNumber LocalizedNumberFormatter::formatInt(int64_t value, 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.setToLong(value);
- 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 {
- 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.setToDouble(value);
- 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 {
- 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.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::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->format(results->quantity, results->getStringRef(), status);
- } else {
- NumberFormatterImpl::formatStatic(fMacros, results->quantity, results->getStringRef(), status);
- }
- if (U_FAILURE(status)) {
- return;
- }
- results->getStringRef().writeTerminator(status);
-}
-
-void LocalizedNumberFormatter::getAffixImpl(bool isPrefix, bool isNegative, UnicodeString& result,
- UErrorCode& status) const {
- FormattedStringBuilder string;
- auto signum = static_cast<Signum>(isNegative ? SIGNUM_NEG : SIGNUM_POS);
- // 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<int32_t>. 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");
- auto* callCount = reinterpret_cast<u_atomic_int32_t*>(
- const_cast<LocalizedNumberFormatter*>(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
- // is exactly threshold, then it is the current thread's job to build the data structure.
- // Note: We set the callCount to INT32_MIN so that if another thread proceeds to increment
- // the atomic int, the value remains below zero.
- int32_t currentCount = umtx_loadAcquire(*callCount);
- if (0 <= currentCount && currentCount <= fMacros.threshold && fMacros.threshold > 0) {
- currentCount = umtx_atomic_inc(callCount);
- }
-
- if (currentCount == fMacros.threshold && fMacros.threshold > 0) {
- // Build the data structure and then use it (slow to fast path).
- const NumberFormatterImpl* compiled = new NumberFormatterImpl(fMacros, status);
- if (compiled == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return false;
- }
- U_ASSERT(fCompiled == nullptr);
- const_cast<LocalizedNumberFormatter*>(this)->fCompiled = compiled;
- umtx_storeRelease(*callCount, INT32_MIN);
- return true;
- } else if (currentCount < 0) {
- // The data structure is already built; use it (fast path).
- U_ASSERT(fCompiled != nullptr);
- return true;
- } else {
- // Format the number without building the data structure (slow path).
- return false;
- }
-}
-
-const impl::NumberFormatterImpl* LocalizedNumberFormatter::getCompiled() const {
- return fCompiled;
-}
-
-int32_t LocalizedNumberFormatter::getCallCount() const {
- auto* callCount = reinterpret_cast<u_atomic_int32_t*>(
- const_cast<LocalizedNumberFormatter*>(this)->fUnsafeCallCount);
- return umtx_loadAcquire(*callCount);
-}
-
-// Note: toFormat defined in number_asformat.cpp
-
-#if (U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN) && defined(_MSC_VER)
-// Warning 4661.
-#pragma warning(pop)
-#endif
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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
+
+#include "uassert.h"
+#include "unicode/numberformatter.h"
+#include "number_decimalquantity.h"
+#include "number_formatimpl.h"
+#include "umutex.h"
+#include "number_asformat.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;
+
+#if (U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN) && defined(_MSC_VER)
+// Ignore MSVC warning 4661. This is generated for NumberFormatterSettings<>::toSkeleton() as this method
+// is defined elsewhere (in number_skeletons.cpp). The compiler is warning that the explicit template instantiation
+// inside this single translation unit (CPP file) is incomplete, and thus it isn't sure if the template class is
+// fully defined. However, since each translation unit explicitly instantiates all the necessary template classes,
+// they will all be passed to the linker, and the linker will still find and export all the class members.
+#pragma warning(push)
+#pragma warning(disable: 4661)
+#endif
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::notation(const Notation& notation) const& {
+ Derived copy(*this);
+ // NOTE: Slicing is OK.
+ copy.fMacros.notation = notation;
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::notation(const Notation& notation)&& {
+ Derived move(std::move(*this));
+ // NOTE: Slicing is OK.
+ move.fMacros.notation = notation;
+ return move;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::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.
+ copy.fMacros.unit = unit;
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::unit(const icu::MeasureUnit& unit)&& {
+ Derived move(std::move(*this));
+ // See comments above about slicing.
+ move.fMacros.unit = unit;
+ return move;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::adoptUnit(icu::MeasureUnit* unit) const& {
+ Derived copy(*this);
+ // 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 = std::move(*unit);
+ delete unit;
+ }
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::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<typename Derived>
+Derived NumberFormatterSettings<Derived>::perUnit(const icu::MeasureUnit& perUnit) const& {
+ Derived copy(*this);
+ // See comments above about slicing.
+ copy.fMacros.perUnit = perUnit;
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::perUnit(const icu::MeasureUnit& perUnit)&& {
+ Derived move(std::move(*this));
+ // See comments above about slicing.
+ move.fMacros.perUnit = perUnit;
+ return move;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::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 = std::move(*perUnit);
+ delete perUnit;
+ }
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::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<typename Derived>
+Derived NumberFormatterSettings<Derived>::precision(const Precision& precision) const& {
+ Derived copy(*this);
+ // NOTE: Slicing is OK.
+ copy.fMacros.precision = precision;
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::precision(const Precision& precision)&& {
+ Derived move(std::move(*this));
+ // NOTE: Slicing is OK.
+ move.fMacros.precision = precision;
+ return move;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::roundingMode(UNumberFormatRoundingMode roundingMode) const& {
+ Derived copy(*this);
+ copy.fMacros.roundingMode = roundingMode;
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::roundingMode(UNumberFormatRoundingMode roundingMode)&& {
+ Derived move(std::move(*this));
+ move.fMacros.roundingMode = roundingMode;
+ return move;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::grouping(UNumberGroupingStrategy 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.
+ copy.fMacros.grouper = Grouper::forStrategy(strategy);
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::grouping(UNumberGroupingStrategy strategy)&& {
+ Derived move(std::move(*this));
+ move.fMacros.grouper = Grouper::forStrategy(strategy);
+ return move;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::integerWidth(const IntegerWidth& style) const& {
+ Derived copy(*this);
+ copy.fMacros.integerWidth = style;
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::integerWidth(const IntegerWidth& style)&& {
+ Derived move(std::move(*this));
+ move.fMacros.integerWidth = style;
+ return move;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::symbols(const DecimalFormatSymbols& symbols) const& {
+ Derived copy(*this);
+ copy.fMacros.symbols.setTo(symbols);
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::symbols(const DecimalFormatSymbols& symbols)&& {
+ Derived move(std::move(*this));
+ move.fMacros.symbols.setTo(symbols);
+ return move;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::adoptSymbols(NumberingSystem* ns) const& {
+ Derived copy(*this);
+ copy.fMacros.symbols.setTo(ns);
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::adoptSymbols(NumberingSystem* ns)&& {
+ Derived move(std::move(*this));
+ move.fMacros.symbols.setTo(ns);
+ return move;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::unitWidth(UNumberUnitWidth width) const& {
+ Derived copy(*this);
+ copy.fMacros.unitWidth = width;
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::unitWidth(UNumberUnitWidth width)&& {
+ Derived move(std::move(*this));
+ move.fMacros.unitWidth = width;
+ return move;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::sign(UNumberSignDisplay style) const& {
+ Derived copy(*this);
+ copy.fMacros.sign = style;
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::sign(UNumberSignDisplay style)&& {
+ Derived move(std::move(*this));
+ move.fMacros.sign = style;
+ return move;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::decimal(UNumberDecimalSeparatorDisplay style) const& {
+ Derived copy(*this);
+ copy.fMacros.decimal = style;
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::decimal(UNumberDecimalSeparatorDisplay style)&& {
+ Derived move(std::move(*this));
+ move.fMacros.decimal = style;
+ return move;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::scale(const Scale& scale) const& {
+ Derived copy(*this);
+ copy.fMacros.scale = scale;
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::scale(const Scale& scale)&& {
+ Derived move(std::move(*this));
+ move.fMacros.scale = scale;
+ return move;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::padding(const Padder& padder) const& {
+ Derived copy(*this);
+ copy.fMacros.padder = padder;
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::padding(const Padder& padder)&& {
+ Derived move(std::move(*this));
+ move.fMacros.padder = padder;
+ return move;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::threshold(int32_t threshold) const& {
+ Derived copy(*this);
+ copy.fMacros.threshold = threshold;
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::threshold(int32_t threshold)&& {
+ Derived move(std::move(*this));
+ move.fMacros.threshold = threshold;
+ return move;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::macros(const impl::MacroProps& macros) const& {
+ Derived copy(*this);
+ copy.fMacros = macros;
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::macros(const impl::MacroProps& macros)&& {
+ Derived move(std::move(*this));
+ move.fMacros = macros;
+ return move;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::macros(impl::MacroProps&& macros) const& {
+ Derived copy(*this);
+ copy.fMacros = std::move(macros);
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberFormatterSettings<Derived>::macros(impl::MacroProps&& macros)&& {
+ Derived move(std::move(*this));
+ move.fMacros = std::move(macros);
+ return move;
+}
+
+// Note: toSkeleton defined in number_skeletons.cpp
+
+template<typename Derived>
+LocalPointer<Derived> NumberFormatterSettings<Derived>::clone() const & {
+ return LocalPointer<Derived>(new Derived(*this));
+}
+
+template<typename Derived>
+LocalPointer<Derived> NumberFormatterSettings<Derived>::clone() && {
+ return LocalPointer<Derived>(new Derived(std::move(*this)));
+}
+
+// Declare all classes that implement NumberFormatterSettings
+// See https://stackoverflow.com/a/495056/1407170
+template
+class icu::number::NumberFormatterSettings<icu::number::UnlocalizedNumberFormatter>;
+template
+class icu::number::NumberFormatterSettings<icu::number::LocalizedNumberFormatter>;
+
+
+UnlocalizedNumberFormatter NumberFormatter::with() {
+ UnlocalizedNumberFormatter result;
+ return result;
+}
+
+LocalizedNumberFormatter NumberFormatter::withLocale(const Locale& locale) {
+ return with().locale(locale);
+}
+
+// Note: forSkeleton defined in number_skeletons.cpp
+
+
+template<typename T> using NFS = NumberFormatterSettings<T>;
+using LNF = LocalizedNumberFormatter;
+using UNF = UnlocalizedNumberFormatter;
+
+UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(const UNF& other)
+ : UNF(static_cast<const NFS<UNF>&>(other)) {}
+
+UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(const NFS<UNF>& other)
+ : NFS<UNF>(other) {
+ // No additional fields to assign
+}
+
+// Make default copy constructor call the NumberFormatterSettings copy constructor.
+UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(UNF&& src) U_NOEXCEPT
+ : UNF(static_cast<NFS<UNF>&&>(src)) {}
+
+UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(NFS<UNF>&& src) U_NOEXCEPT
+ : NFS<UNF>(std::move(src)) {
+ // No additional fields to assign
+}
+
+UnlocalizedNumberFormatter& UnlocalizedNumberFormatter::operator=(const UNF& other) {
+ NFS<UNF>::operator=(static_cast<const NFS<UNF>&>(other));
+ // No additional fields to assign
+ return *this;
+}
+
+UnlocalizedNumberFormatter& UnlocalizedNumberFormatter::operator=(UNF&& src) U_NOEXCEPT {
+ NFS<UNF>::operator=(static_cast<NFS<UNF>&&>(src));
+ // No additional fields to assign
+ return *this;
+}
+
+// Make default copy constructor call the NumberFormatterSettings copy constructor.
+LocalizedNumberFormatter::LocalizedNumberFormatter(const LNF& other)
+ : LNF(static_cast<const NFS<LNF>&>(other)) {}
+
+LocalizedNumberFormatter::LocalizedNumberFormatter(const NFS<LNF>& other)
+ : NFS<LNF>(other) {
+ // No additional fields to assign (let call count and compiled formatter reset to defaults)
+}
+
+LocalizedNumberFormatter::LocalizedNumberFormatter(LocalizedNumberFormatter&& src) U_NOEXCEPT
+ : LNF(static_cast<NFS<LNF>&&>(src)) {}
+
+LocalizedNumberFormatter::LocalizedNumberFormatter(NFS<LNF>&& src) U_NOEXCEPT
+ : NFS<LNF>(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<LNF&&>(src).fCompiled != nullptr) {
+ lnfMoveHelper(static_cast<LNF&&>(src));
+ }
+}
+
+LocalizedNumberFormatter& LocalizedNumberFormatter::operator=(const LNF& other) {
+ NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other));
+ // Reset to default values.
+ clear();
+ return *this;
+}
+
+LocalizedNumberFormatter& LocalizedNumberFormatter::operator=(LNF&& src) U_NOEXCEPT {
+ NFS<LNF>::operator=(static_cast<NFS<LNF>&&>(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<LNF&&>(src).fCompiled != nullptr) {
+ // Formatter is compiled
+ lnfMoveHelper(static_cast<LNF&&>(src));
+ } else {
+ clear();
+ }
+ return *this;
+}
+
+void LocalizedNumberFormatter::clear() {
+ // Reset to default values.
+ auto* callCount = reinterpret_cast<u_atomic_int32_t*>(fUnsafeCallCount);
+ umtx_storeRelease(*callCount, 0);
+ delete fCompiled;
+ fCompiled = nullptr;
+}
+
+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<u_atomic_int32_t*>(fUnsafeCallCount);
+ umtx_storeRelease(*callCount, INT32_MIN);
+ delete fCompiled;
+ fCompiled = src.fCompiled;
+ // Reset the source object to leave it in a safe state.
+ auto* srcCallCount = reinterpret_cast<u_atomic_int32_t*>(src.fUnsafeCallCount);
+ umtx_storeRelease(*srcCallCount, 0);
+ src.fCompiled = nullptr;
+}
+
+
+LocalizedNumberFormatter::~LocalizedNumberFormatter() {
+ delete fCompiled;
+}
+
+LocalizedNumberFormatter::LocalizedNumberFormatter(const MacroProps& macros, const Locale& locale) {
+ fMacros = macros;
+ fMacros.locale = locale;
+}
+
+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);
+}
+
+LocalizedNumberFormatter UnlocalizedNumberFormatter::locale(const Locale& locale)&& {
+ return LocalizedNumberFormatter(std::move(fMacros), locale);
+}
+
+SymbolsWrapper::SymbolsWrapper(const SymbolsWrapper& other) {
+ doCopyFrom(other);
+}
+
+SymbolsWrapper::SymbolsWrapper(SymbolsWrapper&& src) U_NOEXCEPT {
+ doMoveFrom(std::move(src));
+}
+
+SymbolsWrapper& SymbolsWrapper::operator=(const SymbolsWrapper& other) {
+ if (this == &other) {
+ return *this;
+ }
+ doCleanup();
+ doCopyFrom(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) {
+ doCleanup();
+ fType = SYMPTR_DFS;
+ fPtr.dfs = new DecimalFormatSymbols(dfs);
+}
+
+void SymbolsWrapper::setTo(const NumberingSystem* ns) {
+ doCleanup();
+ fType = SYMPTR_NS;
+ fPtr.ns = ns;
+}
+
+void SymbolsWrapper::doCopyFrom(const SymbolsWrapper& other) {
+ fType = other.fType;
+ switch (fType) {
+ case SYMPTR_NONE:
+ // No action necessary
+ break;
+ case SYMPTR_DFS:
+ // Memory allocation failures are exposed in copyErrorTo()
+ if (other.fPtr.dfs != nullptr) {
+ fPtr.dfs = new DecimalFormatSymbols(*other.fPtr.dfs);
+ } else {
+ fPtr.dfs = nullptr;
+ }
+ break;
+ case SYMPTR_NS:
+ // Memory allocation failures are exposed in copyErrorTo()
+ if (other.fPtr.ns != nullptr) {
+ fPtr.ns = new NumberingSystem(*other.fPtr.ns);
+ } else {
+ fPtr.ns = nullptr;
+ }
+ break;
+ }
+}
+
+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:
+ // No action necessary
+ break;
+ case SYMPTR_DFS:
+ delete fPtr.dfs;
+ break;
+ case SYMPTR_NS:
+ delete fPtr.ns;
+ break;
+ }
+}
+
+bool SymbolsWrapper::isDecimalFormatSymbols() const {
+ return fType == SYMPTR_DFS;
+}
+
+bool SymbolsWrapper::isNumberingSystem() const {
+ return fType == SYMPTR_NS;
+}
+
+const DecimalFormatSymbols* SymbolsWrapper::getDecimalFormatSymbols() const {
+ U_ASSERT(fType == SYMPTR_DFS);
+ return fPtr.dfs;
+}
+
+const NumberingSystem* SymbolsWrapper::getNumberingSystem() const {
+ U_ASSERT(fType == SYMPTR_NS);
+ return fPtr.ns;
+}
+
+
+FormattedNumber LocalizedNumberFormatter::formatInt(int64_t value, 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.setToLong(value);
+ 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 {
+ 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.setToDouble(value);
+ 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 {
+ 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.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::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->format(results->quantity, results->getStringRef(), status);
+ } else {
+ NumberFormatterImpl::formatStatic(fMacros, results->quantity, results->getStringRef(), status);
+ }
+ if (U_FAILURE(status)) {
+ return;
+ }
+ results->getStringRef().writeTerminator(status);
+}
+
+void LocalizedNumberFormatter::getAffixImpl(bool isPrefix, bool isNegative, UnicodeString& result,
+ UErrorCode& status) const {
+ FormattedStringBuilder string;
+ auto signum = static_cast<Signum>(isNegative ? SIGNUM_NEG : SIGNUM_POS);
+ // 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<int32_t>. 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");
+ auto* callCount = reinterpret_cast<u_atomic_int32_t*>(
+ const_cast<LocalizedNumberFormatter*>(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
+ // is exactly threshold, then it is the current thread's job to build the data structure.
+ // Note: We set the callCount to INT32_MIN so that if another thread proceeds to increment
+ // the atomic int, the value remains below zero.
+ int32_t currentCount = umtx_loadAcquire(*callCount);
+ if (0 <= currentCount && currentCount <= fMacros.threshold && fMacros.threshold > 0) {
+ currentCount = umtx_atomic_inc(callCount);
+ }
+
+ if (currentCount == fMacros.threshold && fMacros.threshold > 0) {
+ // Build the data structure and then use it (slow to fast path).
+ const NumberFormatterImpl* compiled = new NumberFormatterImpl(fMacros, status);
+ if (compiled == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ U_ASSERT(fCompiled == nullptr);
+ const_cast<LocalizedNumberFormatter*>(this)->fCompiled = compiled;
+ umtx_storeRelease(*callCount, INT32_MIN);
+ return true;
+ } else if (currentCount < 0) {
+ // The data structure is already built; use it (fast path).
+ U_ASSERT(fCompiled != nullptr);
+ return true;
+ } else {
+ // Format the number without building the data structure (slow path).
+ return false;
+ }
+}
+
+const impl::NumberFormatterImpl* LocalizedNumberFormatter::getCompiled() const {
+ return fCompiled;
+}
+
+int32_t LocalizedNumberFormatter::getCallCount() const {
+ auto* callCount = reinterpret_cast<u_atomic_int32_t*>(
+ const_cast<LocalizedNumberFormatter*>(this)->fUnsafeCallCount);
+ return umtx_loadAcquire(*callCount);
+}
+
+// Note: toFormat defined in number_asformat.cpp
+
+#if (U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN) && defined(_MSC_VER)
+// Warning 4661.
+#pragma warning(pop)
+#endif
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_formatimpl.cpp b/contrib/libs/icu/i18n/number_formatimpl.cpp
index 5bba09cfb5..79d53c432c 100644
--- a/contrib/libs/icu/i18n/number_formatimpl.cpp
+++ b/contrib/libs/icu/i18n/number_formatimpl.cpp
@@ -1,536 +1,536 @@
-// © 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
-
-#include "cstring.h"
-#include "unicode/ures.h"
-#include "uresimp.h"
-#include "charstr.h"
-#include "number_formatimpl.h"
-#include "unicode/numfmt.h"
-#include "number_patternstring.h"
-#include "number_utils.h"
-#include "unicode/numberformatter.h"
-#include "unicode/dcfmtsym.h"
-#include "number_scientific.h"
-#include "number_compact.h"
-#include "uresimp.h"
-#include "ureslocs.h"
-
-using namespace icu;
-using namespace icu::number;
-using namespace icu::number::impl;
-
-
-MicroPropsGenerator::~MicroPropsGenerator() = default;
-
-
-NumberFormatterImpl::NumberFormatterImpl(const MacroProps& macros, UErrorCode& status)
- : NumberFormatterImpl(macros, true, status) {
-}
-
-int32_t NumberFormatterImpl::formatStatic(const MacroProps& macros, DecimalQuantity& inValue,
- FormattedStringBuilder& outString, UErrorCode& status) {
- NumberFormatterImpl impl(macros, false, status);
- MicroProps& micros = impl.preProcessUnsafe(inValue, status);
- if (U_FAILURE(status)) { return 0; }
- int32_t length = writeNumber(micros, inValue, outString, 0, status);
- length += writeAffixes(micros, outString, 0, length, status);
- return length;
-}
-
-int32_t NumberFormatterImpl::getPrefixSuffixStatic(const MacroProps& macros, Signum signum,
- StandardPlural::Form plural,
- FormattedStringBuilder& 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.
-
-int32_t NumberFormatterImpl::format(DecimalQuantity& inValue, FormattedStringBuilder& outString,
- UErrorCode& status) const {
- MicroProps micros;
- preProcess(inValue, micros, status);
- if (U_FAILURE(status)) { return 0; }
- int32_t length = writeNumber(micros, inValue, outString, 0, status);
- length += writeAffixes(micros, outString, 0, length, status);
- return length;
-}
-
-void NumberFormatterImpl::preProcess(DecimalQuantity& inValue, MicroProps& microsOut,
- UErrorCode& status) const {
- if (U_FAILURE(status)) { return; }
- if (fMicroPropsGenerator == nullptr) {
- status = U_INTERNAL_PROGRAM_ERROR;
- return;
- }
- fMicroPropsGenerator->processQuantity(inValue, microsOut, status);
- microsOut.integerWidth.apply(inValue, status);
-}
-
-MicroProps& NumberFormatterImpl::preProcessUnsafe(DecimalQuantity& inValue, UErrorCode& status) {
- if (U_FAILURE(status)) {
- return fMicros; // must always return a value
- }
- if (fMicroPropsGenerator == nullptr) {
- status = U_INTERNAL_PROGRAM_ERROR;
- return fMicros; // must always return a value
- }
- fMicroPropsGenerator->processQuantity(inValue, fMicros, status);
- fMicros.integerWidth.apply(inValue, status);
- return fMicros;
-}
-
-int32_t NumberFormatterImpl::getPrefixSuffix(Signum signum, StandardPlural::Form plural,
- FormattedStringBuilder& 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();
-}
-
-int32_t NumberFormatterImpl::getPrefixSuffixUnsafe(Signum signum, StandardPlural::Form plural,
- FormattedStringBuilder& 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();
-}
-
-NumberFormatterImpl::NumberFormatterImpl(const MacroProps& macros, bool safe, UErrorCode& status) {
- fMicroPropsGenerator = macrosToMicroGenerator(macros, safe, status);
-}
-
-//////////
-
-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)) {
- return nullptr;
- }
-
- // TODO: Accept currency symbols from DecimalFormatSymbols?
-
- // Pre-compute a few values for efficiency.
- bool isCurrency = utils::unitIsCurrency(macros.unit);
- bool isNoUnit = utils::unitIsNoUnit(macros.unit);
- bool isPercent = utils::unitIsPercent(macros.unit);
- bool isPermille = utils::unitIsPermille(macros.unit);
- bool isAccounting =
- macros.sign == UNUM_SIGN_ACCOUNTING || macros.sign == UNUM_SIGN_ACCOUNTING_ALWAYS ||
- macros.sign == UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO;
- CurrencyUnit currency(u"", status);
- if (isCurrency) {
- currency = CurrencyUnit(macros.unit, status); // Restore CurrencyUnit from MeasureUnit
- }
- UNumberUnitWidth unitWidth = UNUM_UNIT_WIDTH_SHORT;
- if (macros.unitWidth != UNUM_UNIT_WIDTH_COUNT) {
- unitWidth = macros.unitWidth;
- }
- bool isCldrUnit = !isCurrency && !isNoUnit &&
- (unitWidth == UNUM_UNIT_WIDTH_FULL_NAME || !(isPercent || isPermille));
-
- // Select the numbering system.
- LocalPointer<const NumberingSystem> nsLocal;
- const NumberingSystem* ns;
- if (macros.symbols.isNumberingSystem()) {
- ns = macros.symbols.getNumberingSystem();
- } else {
- // TODO: Is there a way to avoid creating the NumberingSystem object?
- ns = NumberingSystem::createInstance(macros.locale, status);
- // Give ownership to the function scope.
- nsLocal.adoptInstead(ns);
- }
- const char* nsName = U_SUCCESS(status) ? ns->getName() : "latn";
- uprv_strncpy(fMicros.nsName, nsName, 8);
- fMicros.nsName[8] = 0; // guarantee NUL-terminated
-
- // Resolve the symbols. Do this here because currency may need to customize them.
- if (macros.symbols.isDecimalFormatSymbols()) {
- fMicros.symbols = macros.symbols.getDecimalFormatSymbols();
- } else {
- LocalPointer<DecimalFormatSymbols> newSymbols(
- new DecimalFormatSymbols(macros.locale, *ns, status), status);
- if (U_FAILURE(status)) {
- return nullptr;
- }
- if (isCurrency) {
- newSymbols->setCurrency(currency.getISOCurrency(), status);
- if (U_FAILURE(status)) {
- return nullptr;
- }
- }
- fMicros.symbols = newSymbols.getAlias();
- fSymbols.adoptInstead(newSymbols.orphan());
- }
-
- // Load and parse the pattern string. It is used for grouping sizes and affixes only.
- // If we are formatting currency, check for a currency-specific pattern.
- const char16_t* pattern = nullptr;
- if (isCurrency && fMicros.symbols->getCurrencyPattern() != nullptr) {
- pattern = fMicros.symbols->getCurrencyPattern();
- }
- if (pattern == nullptr) {
- CldrPatternStyle patternStyle;
- if (isCldrUnit) {
- patternStyle = CLDR_PATTERN_STYLE_DECIMAL;
- } else if (isPercent || isPermille) {
- patternStyle = CLDR_PATTERN_STYLE_PERCENT;
- } else if (!isCurrency || unitWidth == UNUM_UNIT_WIDTH_FULL_NAME) {
- patternStyle = CLDR_PATTERN_STYLE_DECIMAL;
- } else if (isAccounting) {
- // NOTE: Although ACCOUNTING and ACCOUNTING_ALWAYS are only supported in currencies right now,
- // the API contract allows us to add support to other units in the future.
- patternStyle = CLDR_PATTERN_STYLE_ACCOUNTING;
- } else {
- patternStyle = CLDR_PATTERN_STYLE_CURRENCY;
- }
- pattern = utils::getPatternForStyle(macros.locale, nsName, patternStyle, status);
- if (U_FAILURE(status)) {
- return nullptr;
- }
- }
- auto patternInfo = new ParsedPatternInfo();
- if (patternInfo == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
- fPatternInfo.adoptInstead(patternInfo);
- PatternParser::parseToPatternInfo(UnicodeString(pattern), *patternInfo, status);
- if (U_FAILURE(status)) {
- return nullptr;
- }
-
- /////////////////////////////////////////////////////////////////////////////////////
- /// 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
- Precision precision;
- if (!macros.precision.isBogus()) {
- precision = macros.precision;
- } else if (macros.notation.fType == Notation::NTN_COMPACT) {
- precision = Precision::integer().withMinDigits(2);
- } else if (isCurrency) {
- precision = Precision::currency(UCURR_USAGE_STANDARD);
- } else {
- precision = Precision::maxFraction(6);
- }
- UNumberFormatRoundingMode roundingMode;
- if (macros.roundingMode != kDefaultMode) {
- roundingMode = macros.roundingMode;
- } else {
- // Temporary until ICU 64
- roundingMode = precision.fRoundingMode;
- }
- fMicros.rounder = {precision, roundingMode, currency, status};
- if (U_FAILURE(status)) {
- return nullptr;
- }
-
- // Grouping strategy
- if (!macros.grouper.isBogus()) {
- fMicros.grouping = macros.grouper;
- } else if (macros.notation.fType == Notation::NTN_COMPACT) {
- // Compact notation uses minGrouping by default since ICU 59
- fMicros.grouping = Grouper::forStrategy(UNUM_GROUPING_MIN2);
- } else {
- fMicros.grouping = Grouper::forStrategy(UNUM_GROUPING_AUTO);
- }
- fMicros.grouping.setLocaleData(*fPatternInfo, macros.locale);
-
- // Padding strategy
- if (!macros.padder.isBogus()) {
- fMicros.padding = macros.padder;
- } else {
- fMicros.padding = Padder::none();
- }
-
- // Integer width
- if (!macros.integerWidth.isBogus()) {
- fMicros.integerWidth = macros.integerWidth;
- } else {
- fMicros.integerWidth = IntegerWidth::standard();
- }
-
- // Sign display
- if (macros.sign != UNUM_SIGN_COUNT) {
- fMicros.sign = macros.sign;
- } else {
- fMicros.sign = UNUM_SIGN_AUTO;
- }
-
- // Decimal mark display
- if (macros.decimal != UNUM_DECIMAL_SEPARATOR_COUNT) {
- fMicros.decimal = macros.decimal;
- } else {
- fMicros.decimal = UNUM_DECIMAL_SEPARATOR_AUTO;
- }
-
- // Use monetary separator symbols
- fMicros.useCurrency = isCurrency;
-
- // Inner modifier (scientific notation)
- if (macros.notation.fType == Notation::NTN_SCIENTIFIC) {
- auto newScientificHandler = new ScientificHandler(&macros.notation, fMicros.symbols, chain);
- if (newScientificHandler == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
- fScientificHandler.adoptInstead(newScientificHandler);
- chain = fScientificHandler.getAlias();
- } else {
- // No inner modifier required
- fMicros.modInner = &fMicros.helpers.emptyStrongModifier;
- }
-
- // Middle modifier (patterns, positive/negative, currency symbols, percent)
- auto patternModifier = new MutablePatternModifier(false);
- if (patternModifier == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
- fPatternModifier.adoptInstead(patternModifier);
- patternModifier->setPatternInfo(
- macros.affixProvider != nullptr ? macros.affixProvider
- : static_cast<const AffixPatternProvider*>(fPatternInfo.getAlias()),
- kUndefinedField);
- patternModifier->setPatternAttributes(fMicros.sign, isPermille);
- if (patternModifier->needsPlurals()) {
- patternModifier->setSymbols(
- fMicros.symbols,
- currency,
- unitWidth,
- resolvePluralRules(macros.rules, macros.locale, status),
- status);
- } else {
- patternModifier->setSymbols(fMicros.symbols, currency, unitWidth, nullptr, status);
- }
- if (safe) {
- fImmutablePatternModifier.adoptInstead(patternModifier->createImmutable(status));
- }
- if (U_FAILURE(status)) {
- return nullptr;
- }
-
- // Outer modifier (CLDR units and currency long names)
- if (isCldrUnit) {
- fLongNameHandler.adoptInstead(
- LongNameHandler::forMeasureUnit(
- macros.locale,
- macros.unit,
- macros.perUnit,
- unitWidth,
- resolvePluralRules(macros.rules, macros.locale, status),
- chain,
- status));
- chain = fLongNameHandler.getAlias();
- } else if (isCurrency && unitWidth == UNUM_UNIT_WIDTH_FULL_NAME) {
- fLongNameHandler.adoptInstead(
- LongNameHandler::forCurrencyLongNames(
- macros.locale,
- currency,
- resolvePluralRules(macros.rules, macros.locale, status),
- chain,
- status));
- chain = fLongNameHandler.getAlias();
- } else {
- // No outer modifier required
- fMicros.modOuter = &fMicros.helpers.emptyWeakModifier;
- }
- if (U_FAILURE(status)) {
- return nullptr;
- }
-
- // Compact notation
- if (macros.notation.fType == Notation::NTN_COMPACT) {
- CompactType compactType = (isCurrency && unitWidth != UNUM_UNIT_WIDTH_FULL_NAME)
- ? CompactType::TYPE_CURRENCY : CompactType::TYPE_DECIMAL;
- auto newCompactHandler = new CompactHandler(
- macros.notation.fUnion.compactStyle,
- macros.locale,
- nsName,
- compactType,
- resolvePluralRules(macros.rules, macros.locale, status),
- patternModifier,
- safe,
- chain,
- status);
- if (newCompactHandler == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
- fCompactHandler.adoptInstead(newCompactHandler);
- chain = fCompactHandler.getAlias();
- }
- if (U_FAILURE(status)) {
- return nullptr;
- }
-
- // Always add the pattern modifier as the last element of the chain.
- if (safe) {
- fImmutablePatternModifier->addToChain(chain);
- chain = fImmutablePatternModifier.getAlias();
- } else {
- patternModifier->addToChain(chain);
- chain = patternModifier;
- }
-
- return chain;
-}
-
-const PluralRules*
-NumberFormatterImpl::resolvePluralRules(const PluralRules* rulesPtr, const Locale& locale,
- UErrorCode& status) {
- if (rulesPtr != nullptr) {
- return rulesPtr;
- }
- // Lazily create PluralRules
- if (fRules.isNull()) {
- fRules.adoptInstead(PluralRules::forLocale(locale, status));
- }
- return fRules.getAlias();
-}
-
-int32_t NumberFormatterImpl::writeAffixes(const MicroProps& micros, FormattedStringBuilder& string,
- int32_t start, int32_t end, UErrorCode& status) {
- // Always apply the inner modifier (which is "strong").
- int32_t length = micros.modInner->apply(string, start, end, status);
- if (micros.padding.isValid()) {
- length += micros.padding
- .padAndApply(*micros.modMiddle, *micros.modOuter, string, start, length + end, status);
- } else {
- length += micros.modMiddle->apply(string, start, length + end, status);
- length += micros.modOuter->apply(string, start, length + end, status);
- }
- return length;
-}
-
-int32_t NumberFormatterImpl::writeNumber(const MicroProps& micros, DecimalQuantity& quantity,
- FormattedStringBuilder& string, int32_t index,
- UErrorCode& status) {
- int32_t length = 0;
- if (quantity.isInfinite()) {
- length += string.insert(
- length + index,
- micros.symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kInfinitySymbol),
- {UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD},
- status);
-
- } else if (quantity.isNaN()) {
- length += string.insert(
- length + index,
- micros.symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kNaNSymbol),
- {UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD},
- status);
-
- } else {
- // Add the integer digits
- length += writeIntegerDigits(micros, quantity, string, length + index, status);
-
- // Add the decimal point
- if (quantity.getLowerDisplayMagnitude() < 0 || micros.decimal == UNUM_DECIMAL_SEPARATOR_ALWAYS) {
- length += string.insert(
- length + index,
- micros.useCurrency ? micros.symbols->getSymbol(
- DecimalFormatSymbols::ENumberFormatSymbol::kMonetarySeparatorSymbol) : micros
- .symbols
- ->getSymbol(
- DecimalFormatSymbols::ENumberFormatSymbol::kDecimalSeparatorSymbol),
- {UFIELD_CATEGORY_NUMBER, UNUM_DECIMAL_SEPARATOR_FIELD},
- status);
- }
-
- // Add the fraction digits
- length += writeFractionDigits(micros, quantity, string, length + index, status);
-
- if (length == 0) {
- // Force output of the digit for value 0
- length += utils::insertDigitFromSymbols(
- string,
- index,
- 0,
- *micros.symbols,
- {UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD},
- status);
- }
- }
-
- return length;
-}
-
-int32_t NumberFormatterImpl::writeIntegerDigits(const MicroProps& micros, DecimalQuantity& quantity,
- FormattedStringBuilder& string, int32_t index,
- UErrorCode& status) {
- int length = 0;
- int integerCount = quantity.getUpperDisplayMagnitude() + 1;
- for (int i = 0; i < integerCount; i++) {
- // Add grouping separator
- if (micros.grouping.groupAtPosition(i, quantity)) {
- length += string.insert(
- index,
- micros.useCurrency ? micros.symbols->getSymbol(
- DecimalFormatSymbols::ENumberFormatSymbol::kMonetaryGroupingSeparatorSymbol)
- : micros.symbols->getSymbol(
- DecimalFormatSymbols::ENumberFormatSymbol::kGroupingSeparatorSymbol),
- {UFIELD_CATEGORY_NUMBER, UNUM_GROUPING_SEPARATOR_FIELD},
- status);
- }
-
- // Get and append the next digit value
- int8_t nextDigit = quantity.getDigit(i);
- length += utils::insertDigitFromSymbols(
- string,
- index,
- nextDigit,
- *micros.symbols,
- {UFIELD_CATEGORY_NUMBER,
- UNUM_INTEGER_FIELD},
- status);
- }
- return length;
-}
-
-int32_t NumberFormatterImpl::writeFractionDigits(const MicroProps& micros, DecimalQuantity& quantity,
- FormattedStringBuilder& string, int32_t index,
- 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 += utils::insertDigitFromSymbols(
- string,
- length + index,
- nextDigit,
- *micros.symbols,
- {UFIELD_CATEGORY_NUMBER, UNUM_FRACTION_FIELD},
- status);
- }
- return length;
-}
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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
+
+#include "cstring.h"
+#include "unicode/ures.h"
+#include "uresimp.h"
+#include "charstr.h"
+#include "number_formatimpl.h"
+#include "unicode/numfmt.h"
+#include "number_patternstring.h"
+#include "number_utils.h"
+#include "unicode/numberformatter.h"
+#include "unicode/dcfmtsym.h"
+#include "number_scientific.h"
+#include "number_compact.h"
+#include "uresimp.h"
+#include "ureslocs.h"
+
+using namespace icu;
+using namespace icu::number;
+using namespace icu::number::impl;
+
+
+MicroPropsGenerator::~MicroPropsGenerator() = default;
+
+
+NumberFormatterImpl::NumberFormatterImpl(const MacroProps& macros, UErrorCode& status)
+ : NumberFormatterImpl(macros, true, status) {
+}
+
+int32_t NumberFormatterImpl::formatStatic(const MacroProps& macros, DecimalQuantity& inValue,
+ FormattedStringBuilder& outString, UErrorCode& status) {
+ NumberFormatterImpl impl(macros, false, status);
+ MicroProps& micros = impl.preProcessUnsafe(inValue, status);
+ if (U_FAILURE(status)) { return 0; }
+ int32_t length = writeNumber(micros, inValue, outString, 0, status);
+ length += writeAffixes(micros, outString, 0, length, status);
+ return length;
+}
+
+int32_t NumberFormatterImpl::getPrefixSuffixStatic(const MacroProps& macros, Signum signum,
+ StandardPlural::Form plural,
+ FormattedStringBuilder& 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.
+
+int32_t NumberFormatterImpl::format(DecimalQuantity& inValue, FormattedStringBuilder& outString,
+ UErrorCode& status) const {
+ MicroProps micros;
+ preProcess(inValue, micros, status);
+ if (U_FAILURE(status)) { return 0; }
+ int32_t length = writeNumber(micros, inValue, outString, 0, status);
+ length += writeAffixes(micros, outString, 0, length, status);
+ return length;
+}
+
+void NumberFormatterImpl::preProcess(DecimalQuantity& inValue, MicroProps& microsOut,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) { return; }
+ if (fMicroPropsGenerator == nullptr) {
+ status = U_INTERNAL_PROGRAM_ERROR;
+ return;
+ }
+ fMicroPropsGenerator->processQuantity(inValue, microsOut, status);
+ microsOut.integerWidth.apply(inValue, status);
+}
+
+MicroProps& NumberFormatterImpl::preProcessUnsafe(DecimalQuantity& inValue, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return fMicros; // must always return a value
+ }
+ if (fMicroPropsGenerator == nullptr) {
+ status = U_INTERNAL_PROGRAM_ERROR;
+ return fMicros; // must always return a value
+ }
+ fMicroPropsGenerator->processQuantity(inValue, fMicros, status);
+ fMicros.integerWidth.apply(inValue, status);
+ return fMicros;
+}
+
+int32_t NumberFormatterImpl::getPrefixSuffix(Signum signum, StandardPlural::Form plural,
+ FormattedStringBuilder& 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();
+}
+
+int32_t NumberFormatterImpl::getPrefixSuffixUnsafe(Signum signum, StandardPlural::Form plural,
+ FormattedStringBuilder& 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();
+}
+
+NumberFormatterImpl::NumberFormatterImpl(const MacroProps& macros, bool safe, UErrorCode& status) {
+ fMicroPropsGenerator = macrosToMicroGenerator(macros, safe, status);
+}
+
+//////////
+
+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)) {
+ return nullptr;
+ }
+
+ // TODO: Accept currency symbols from DecimalFormatSymbols?
+
+ // Pre-compute a few values for efficiency.
+ bool isCurrency = utils::unitIsCurrency(macros.unit);
+ bool isNoUnit = utils::unitIsNoUnit(macros.unit);
+ bool isPercent = utils::unitIsPercent(macros.unit);
+ bool isPermille = utils::unitIsPermille(macros.unit);
+ bool isAccounting =
+ macros.sign == UNUM_SIGN_ACCOUNTING || macros.sign == UNUM_SIGN_ACCOUNTING_ALWAYS ||
+ macros.sign == UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO;
+ CurrencyUnit currency(u"", status);
+ if (isCurrency) {
+ currency = CurrencyUnit(macros.unit, status); // Restore CurrencyUnit from MeasureUnit
+ }
+ UNumberUnitWidth unitWidth = UNUM_UNIT_WIDTH_SHORT;
+ if (macros.unitWidth != UNUM_UNIT_WIDTH_COUNT) {
+ unitWidth = macros.unitWidth;
+ }
+ bool isCldrUnit = !isCurrency && !isNoUnit &&
+ (unitWidth == UNUM_UNIT_WIDTH_FULL_NAME || !(isPercent || isPermille));
+
+ // Select the numbering system.
+ LocalPointer<const NumberingSystem> nsLocal;
+ const NumberingSystem* ns;
+ if (macros.symbols.isNumberingSystem()) {
+ ns = macros.symbols.getNumberingSystem();
+ } else {
+ // TODO: Is there a way to avoid creating the NumberingSystem object?
+ ns = NumberingSystem::createInstance(macros.locale, status);
+ // Give ownership to the function scope.
+ nsLocal.adoptInstead(ns);
+ }
+ const char* nsName = U_SUCCESS(status) ? ns->getName() : "latn";
+ uprv_strncpy(fMicros.nsName, nsName, 8);
+ fMicros.nsName[8] = 0; // guarantee NUL-terminated
+
+ // Resolve the symbols. Do this here because currency may need to customize them.
+ if (macros.symbols.isDecimalFormatSymbols()) {
+ fMicros.symbols = macros.symbols.getDecimalFormatSymbols();
+ } else {
+ LocalPointer<DecimalFormatSymbols> newSymbols(
+ new DecimalFormatSymbols(macros.locale, *ns, status), status);
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ if (isCurrency) {
+ newSymbols->setCurrency(currency.getISOCurrency(), status);
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ }
+ fMicros.symbols = newSymbols.getAlias();
+ fSymbols.adoptInstead(newSymbols.orphan());
+ }
+
+ // Load and parse the pattern string. It is used for grouping sizes and affixes only.
+ // If we are formatting currency, check for a currency-specific pattern.
+ const char16_t* pattern = nullptr;
+ if (isCurrency && fMicros.symbols->getCurrencyPattern() != nullptr) {
+ pattern = fMicros.symbols->getCurrencyPattern();
+ }
+ if (pattern == nullptr) {
+ CldrPatternStyle patternStyle;
+ if (isCldrUnit) {
+ patternStyle = CLDR_PATTERN_STYLE_DECIMAL;
+ } else if (isPercent || isPermille) {
+ patternStyle = CLDR_PATTERN_STYLE_PERCENT;
+ } else if (!isCurrency || unitWidth == UNUM_UNIT_WIDTH_FULL_NAME) {
+ patternStyle = CLDR_PATTERN_STYLE_DECIMAL;
+ } else if (isAccounting) {
+ // NOTE: Although ACCOUNTING and ACCOUNTING_ALWAYS are only supported in currencies right now,
+ // the API contract allows us to add support to other units in the future.
+ patternStyle = CLDR_PATTERN_STYLE_ACCOUNTING;
+ } else {
+ patternStyle = CLDR_PATTERN_STYLE_CURRENCY;
+ }
+ pattern = utils::getPatternForStyle(macros.locale, nsName, patternStyle, status);
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ }
+ auto patternInfo = new ParsedPatternInfo();
+ if (patternInfo == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+ fPatternInfo.adoptInstead(patternInfo);
+ PatternParser::parseToPatternInfo(UnicodeString(pattern), *patternInfo, status);
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////////
+ /// 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
+ Precision precision;
+ if (!macros.precision.isBogus()) {
+ precision = macros.precision;
+ } else if (macros.notation.fType == Notation::NTN_COMPACT) {
+ precision = Precision::integer().withMinDigits(2);
+ } else if (isCurrency) {
+ precision = Precision::currency(UCURR_USAGE_STANDARD);
+ } else {
+ precision = Precision::maxFraction(6);
+ }
+ UNumberFormatRoundingMode roundingMode;
+ if (macros.roundingMode != kDefaultMode) {
+ roundingMode = macros.roundingMode;
+ } else {
+ // Temporary until ICU 64
+ roundingMode = precision.fRoundingMode;
+ }
+ fMicros.rounder = {precision, roundingMode, currency, status};
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+
+ // Grouping strategy
+ if (!macros.grouper.isBogus()) {
+ fMicros.grouping = macros.grouper;
+ } else if (macros.notation.fType == Notation::NTN_COMPACT) {
+ // Compact notation uses minGrouping by default since ICU 59
+ fMicros.grouping = Grouper::forStrategy(UNUM_GROUPING_MIN2);
+ } else {
+ fMicros.grouping = Grouper::forStrategy(UNUM_GROUPING_AUTO);
+ }
+ fMicros.grouping.setLocaleData(*fPatternInfo, macros.locale);
+
+ // Padding strategy
+ if (!macros.padder.isBogus()) {
+ fMicros.padding = macros.padder;
+ } else {
+ fMicros.padding = Padder::none();
+ }
+
+ // Integer width
+ if (!macros.integerWidth.isBogus()) {
+ fMicros.integerWidth = macros.integerWidth;
+ } else {
+ fMicros.integerWidth = IntegerWidth::standard();
+ }
+
+ // Sign display
+ if (macros.sign != UNUM_SIGN_COUNT) {
+ fMicros.sign = macros.sign;
+ } else {
+ fMicros.sign = UNUM_SIGN_AUTO;
+ }
+
+ // Decimal mark display
+ if (macros.decimal != UNUM_DECIMAL_SEPARATOR_COUNT) {
+ fMicros.decimal = macros.decimal;
+ } else {
+ fMicros.decimal = UNUM_DECIMAL_SEPARATOR_AUTO;
+ }
+
+ // Use monetary separator symbols
+ fMicros.useCurrency = isCurrency;
+
+ // Inner modifier (scientific notation)
+ if (macros.notation.fType == Notation::NTN_SCIENTIFIC) {
+ auto newScientificHandler = new ScientificHandler(&macros.notation, fMicros.symbols, chain);
+ if (newScientificHandler == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+ fScientificHandler.adoptInstead(newScientificHandler);
+ chain = fScientificHandler.getAlias();
+ } else {
+ // No inner modifier required
+ fMicros.modInner = &fMicros.helpers.emptyStrongModifier;
+ }
+
+ // Middle modifier (patterns, positive/negative, currency symbols, percent)
+ auto patternModifier = new MutablePatternModifier(false);
+ if (patternModifier == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+ fPatternModifier.adoptInstead(patternModifier);
+ patternModifier->setPatternInfo(
+ macros.affixProvider != nullptr ? macros.affixProvider
+ : static_cast<const AffixPatternProvider*>(fPatternInfo.getAlias()),
+ kUndefinedField);
+ patternModifier->setPatternAttributes(fMicros.sign, isPermille);
+ if (patternModifier->needsPlurals()) {
+ patternModifier->setSymbols(
+ fMicros.symbols,
+ currency,
+ unitWidth,
+ resolvePluralRules(macros.rules, macros.locale, status),
+ status);
+ } else {
+ patternModifier->setSymbols(fMicros.symbols, currency, unitWidth, nullptr, status);
+ }
+ if (safe) {
+ fImmutablePatternModifier.adoptInstead(patternModifier->createImmutable(status));
+ }
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+
+ // Outer modifier (CLDR units and currency long names)
+ if (isCldrUnit) {
+ fLongNameHandler.adoptInstead(
+ LongNameHandler::forMeasureUnit(
+ macros.locale,
+ macros.unit,
+ macros.perUnit,
+ unitWidth,
+ resolvePluralRules(macros.rules, macros.locale, status),
+ chain,
+ status));
+ chain = fLongNameHandler.getAlias();
+ } else if (isCurrency && unitWidth == UNUM_UNIT_WIDTH_FULL_NAME) {
+ fLongNameHandler.adoptInstead(
+ LongNameHandler::forCurrencyLongNames(
+ macros.locale,
+ currency,
+ resolvePluralRules(macros.rules, macros.locale, status),
+ chain,
+ status));
+ chain = fLongNameHandler.getAlias();
+ } else {
+ // No outer modifier required
+ fMicros.modOuter = &fMicros.helpers.emptyWeakModifier;
+ }
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+
+ // Compact notation
+ if (macros.notation.fType == Notation::NTN_COMPACT) {
+ CompactType compactType = (isCurrency && unitWidth != UNUM_UNIT_WIDTH_FULL_NAME)
+ ? CompactType::TYPE_CURRENCY : CompactType::TYPE_DECIMAL;
+ auto newCompactHandler = new CompactHandler(
+ macros.notation.fUnion.compactStyle,
+ macros.locale,
+ nsName,
+ compactType,
+ resolvePluralRules(macros.rules, macros.locale, status),
+ patternModifier,
+ safe,
+ chain,
+ status);
+ if (newCompactHandler == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+ fCompactHandler.adoptInstead(newCompactHandler);
+ chain = fCompactHandler.getAlias();
+ }
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+
+ // Always add the pattern modifier as the last element of the chain.
+ if (safe) {
+ fImmutablePatternModifier->addToChain(chain);
+ chain = fImmutablePatternModifier.getAlias();
+ } else {
+ patternModifier->addToChain(chain);
+ chain = patternModifier;
+ }
+
+ return chain;
+}
+
+const PluralRules*
+NumberFormatterImpl::resolvePluralRules(const PluralRules* rulesPtr, const Locale& locale,
+ UErrorCode& status) {
+ if (rulesPtr != nullptr) {
+ return rulesPtr;
+ }
+ // Lazily create PluralRules
+ if (fRules.isNull()) {
+ fRules.adoptInstead(PluralRules::forLocale(locale, status));
+ }
+ return fRules.getAlias();
+}
+
+int32_t NumberFormatterImpl::writeAffixes(const MicroProps& micros, FormattedStringBuilder& string,
+ int32_t start, int32_t end, UErrorCode& status) {
+ // Always apply the inner modifier (which is "strong").
+ int32_t length = micros.modInner->apply(string, start, end, status);
+ if (micros.padding.isValid()) {
+ length += micros.padding
+ .padAndApply(*micros.modMiddle, *micros.modOuter, string, start, length + end, status);
+ } else {
+ length += micros.modMiddle->apply(string, start, length + end, status);
+ length += micros.modOuter->apply(string, start, length + end, status);
+ }
+ return length;
+}
+
+int32_t NumberFormatterImpl::writeNumber(const MicroProps& micros, DecimalQuantity& quantity,
+ FormattedStringBuilder& string, int32_t index,
+ UErrorCode& status) {
+ int32_t length = 0;
+ if (quantity.isInfinite()) {
+ length += string.insert(
+ length + index,
+ micros.symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kInfinitySymbol),
+ {UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD},
+ status);
+
+ } else if (quantity.isNaN()) {
+ length += string.insert(
+ length + index,
+ micros.symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kNaNSymbol),
+ {UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD},
+ status);
+
+ } else {
+ // Add the integer digits
+ length += writeIntegerDigits(micros, quantity, string, length + index, status);
+
+ // Add the decimal point
+ if (quantity.getLowerDisplayMagnitude() < 0 || micros.decimal == UNUM_DECIMAL_SEPARATOR_ALWAYS) {
+ length += string.insert(
+ length + index,
+ micros.useCurrency ? micros.symbols->getSymbol(
+ DecimalFormatSymbols::ENumberFormatSymbol::kMonetarySeparatorSymbol) : micros
+ .symbols
+ ->getSymbol(
+ DecimalFormatSymbols::ENumberFormatSymbol::kDecimalSeparatorSymbol),
+ {UFIELD_CATEGORY_NUMBER, UNUM_DECIMAL_SEPARATOR_FIELD},
+ status);
+ }
+
+ // Add the fraction digits
+ length += writeFractionDigits(micros, quantity, string, length + index, status);
+
+ if (length == 0) {
+ // Force output of the digit for value 0
+ length += utils::insertDigitFromSymbols(
+ string,
+ index,
+ 0,
+ *micros.symbols,
+ {UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD},
+ status);
+ }
+ }
+
+ return length;
+}
+
+int32_t NumberFormatterImpl::writeIntegerDigits(const MicroProps& micros, DecimalQuantity& quantity,
+ FormattedStringBuilder& string, int32_t index,
+ UErrorCode& status) {
+ int length = 0;
+ int integerCount = quantity.getUpperDisplayMagnitude() + 1;
+ for (int i = 0; i < integerCount; i++) {
+ // Add grouping separator
+ if (micros.grouping.groupAtPosition(i, quantity)) {
+ length += string.insert(
+ index,
+ micros.useCurrency ? micros.symbols->getSymbol(
+ DecimalFormatSymbols::ENumberFormatSymbol::kMonetaryGroupingSeparatorSymbol)
+ : micros.symbols->getSymbol(
+ DecimalFormatSymbols::ENumberFormatSymbol::kGroupingSeparatorSymbol),
+ {UFIELD_CATEGORY_NUMBER, UNUM_GROUPING_SEPARATOR_FIELD},
+ status);
+ }
+
+ // Get and append the next digit value
+ int8_t nextDigit = quantity.getDigit(i);
+ length += utils::insertDigitFromSymbols(
+ string,
+ index,
+ nextDigit,
+ *micros.symbols,
+ {UFIELD_CATEGORY_NUMBER,
+ UNUM_INTEGER_FIELD},
+ status);
+ }
+ return length;
+}
+
+int32_t NumberFormatterImpl::writeFractionDigits(const MicroProps& micros, DecimalQuantity& quantity,
+ FormattedStringBuilder& string, int32_t index,
+ 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 += utils::insertDigitFromSymbols(
+ string,
+ length + index,
+ nextDigit,
+ *micros.symbols,
+ {UFIELD_CATEGORY_NUMBER, UNUM_FRACTION_FIELD},
+ status);
+ }
+ return length;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_formatimpl.h b/contrib/libs/icu/i18n/number_formatimpl.h
index 084bc4a9d0..c06f0dd898 100644
--- a/contrib/libs/icu/i18n/number_formatimpl.h
+++ b/contrib/libs/icu/i18n/number_formatimpl.h
@@ -1,154 +1,154 @@
-// © 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_FORMATIMPL_H__
-#define __NUMBER_FORMATIMPL_H__
-
-#include "number_types.h"
-#include "formatted_string_builder.h"
-#include "number_patternstring.h"
-#include "number_utils.h"
-#include "number_patternmodifier.h"
-#include "number_longnames.h"
-#include "number_compact.h"
-#include "number_microprops.h"
-
-U_NAMESPACE_BEGIN namespace number {
-namespace impl {
-
-/**
- * This is the "brain" of the number formatting pipeline. It ties all the pieces together, taking in a MacroProps and a
- * DecimalQuantity and outputting a properly formatted number string.
- */
-class NumberFormatterImpl : public UMemory {
- public:
- /**
- * Builds a "safe" MicroPropsGenerator, which is thread-safe and can be used repeatedly.
- * The caller owns the returned NumberFormatterImpl.
- */
- NumberFormatterImpl(const MacroProps &macros, UErrorCode &status);
-
- /**
- * Builds and evaluates an "unsafe" MicroPropsGenerator, which is cheaper but can be used only once.
- */
- static int32_t
- formatStatic(const MacroProps &macros, DecimalQuantity &inValue, FormattedStringBuilder &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, Signum signum,
- StandardPlural::Form plural, FormattedStringBuilder& outString,
- UErrorCode& status);
-
- /**
- * Evaluates the "safe" MicroPropsGenerator created by "fromMacros".
- */
- int32_t format(DecimalQuantity& inValue, FormattedStringBuilder& outString, UErrorCode& status) const;
-
- /**
- * Like format(), but saves the result into an output MicroProps without additional processing.
- */
- void preProcess(DecimalQuantity& inValue, MicroProps& microsOut, UErrorCode& status) const;
-
- /**
- * Like getPrefixSuffixStatic() but uses the safe compiled object.
- */
- int32_t getPrefixSuffix(Signum signum, StandardPlural::Form plural, FormattedStringBuilder& outString,
- UErrorCode& status) const;
-
- const MicroProps& getRawMicroProps() const {
- return fMicros;
- }
-
- /**
- * Synthesizes the output string from a MicroProps and DecimalQuantity.
- * This method formats only the main number, not affixes.
- */
- static int32_t writeNumber(const MicroProps& micros, DecimalQuantity& quantity,
- FormattedStringBuilder& string, int32_t index, UErrorCode& status);
-
- /**
- * Adds the affixes. Intended to be called immediately after formatNumber.
- */
- static int32_t writeAffixes(const MicroProps& micros, FormattedStringBuilder& string, int32_t start,
- int32_t end, UErrorCode& status);
-
- private:
- // Head of the MicroPropsGenerator linked list:
- const MicroPropsGenerator *fMicroPropsGenerator = nullptr;
-
- // Tail of the list:
- MicroProps fMicros;
-
- // Other fields possibly used by the number formatting pipeline:
- // TODO: Convert more of these LocalPointers to value objects to reduce the number of news?
- LocalPointer<const DecimalFormatSymbols> fSymbols;
- LocalPointer<const PluralRules> fRules;
- LocalPointer<const ParsedPatternInfo> fPatternInfo;
- LocalPointer<const ScientificHandler> fScientificHandler;
- LocalPointer<MutablePatternModifier> fPatternModifier;
- LocalPointer<ImmutablePatternModifier> fImmutablePatternModifier;
- LocalPointer<const LongNameHandler> fLongNameHandler;
- LocalPointer<const CompactHandler> fCompactHandler;
-
- // Value objects possibly used by the number formatting pipeline:
- struct Warehouse {
- CurrencySymbols fCurrencySymbols;
- } fWarehouse;
-
-
- NumberFormatterImpl(const MacroProps &macros, bool safe, UErrorCode &status);
-
- MicroProps& preProcessUnsafe(DecimalQuantity &inValue, UErrorCode &status);
-
- int32_t getPrefixSuffixUnsafe(Signum signum, StandardPlural::Form plural,
- FormattedStringBuilder& 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.
- */
- const PluralRules *
- resolvePluralRules(const PluralRules *rulesPtr, const Locale &locale, UErrorCode &status);
-
- /**
- * Synthesizes the MacroProps into a MicroPropsGenerator. All information, including the locale, is encoded into the
- * MicroPropsGenerator, except for the quantity itself, which is left abstract and must be provided to the returned
- * MicroPropsGenerator instance.
- *
- * @see MicroPropsGenerator
- * @param macros
- * The {@link MacroProps} to consume. This method does not mutate the MacroProps instance.
- * @param safe
- * If true, the returned MicroPropsGenerator will be thread-safe. If false, the returned value will
- * <em>not</em> be thread-safe, intended for a single "one-shot" use only. Building the thread-safe
- * object is more expensive.
- */
- const MicroPropsGenerator *
- macrosToMicroGenerator(const MacroProps &macros, bool safe, UErrorCode &status);
-
- static int32_t
- writeIntegerDigits(const MicroProps &micros, DecimalQuantity &quantity, FormattedStringBuilder &string,
- int32_t index, UErrorCode &status);
-
- static int32_t
- writeFractionDigits(const MicroProps &micros, DecimalQuantity &quantity, FormattedStringBuilder &string,
- int32_t index, UErrorCode &status);
-};
-
-} // namespace impl
-} // namespace number
-U_NAMESPACE_END
-
-
-#endif //__NUMBER_FORMATIMPL_H__
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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_FORMATIMPL_H__
+#define __NUMBER_FORMATIMPL_H__
+
+#include "number_types.h"
+#include "formatted_string_builder.h"
+#include "number_patternstring.h"
+#include "number_utils.h"
+#include "number_patternmodifier.h"
+#include "number_longnames.h"
+#include "number_compact.h"
+#include "number_microprops.h"
+
+U_NAMESPACE_BEGIN namespace number {
+namespace impl {
+
+/**
+ * This is the "brain" of the number formatting pipeline. It ties all the pieces together, taking in a MacroProps and a
+ * DecimalQuantity and outputting a properly formatted number string.
+ */
+class NumberFormatterImpl : public UMemory {
+ public:
+ /**
+ * Builds a "safe" MicroPropsGenerator, which is thread-safe and can be used repeatedly.
+ * The caller owns the returned NumberFormatterImpl.
+ */
+ NumberFormatterImpl(const MacroProps &macros, UErrorCode &status);
+
+ /**
+ * Builds and evaluates an "unsafe" MicroPropsGenerator, which is cheaper but can be used only once.
+ */
+ static int32_t
+ formatStatic(const MacroProps &macros, DecimalQuantity &inValue, FormattedStringBuilder &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, Signum signum,
+ StandardPlural::Form plural, FormattedStringBuilder& outString,
+ UErrorCode& status);
+
+ /**
+ * Evaluates the "safe" MicroPropsGenerator created by "fromMacros".
+ */
+ int32_t format(DecimalQuantity& inValue, FormattedStringBuilder& outString, UErrorCode& status) const;
+
+ /**
+ * Like format(), but saves the result into an output MicroProps without additional processing.
+ */
+ void preProcess(DecimalQuantity& inValue, MicroProps& microsOut, UErrorCode& status) const;
+
+ /**
+ * Like getPrefixSuffixStatic() but uses the safe compiled object.
+ */
+ int32_t getPrefixSuffix(Signum signum, StandardPlural::Form plural, FormattedStringBuilder& outString,
+ UErrorCode& status) const;
+
+ const MicroProps& getRawMicroProps() const {
+ return fMicros;
+ }
+
+ /**
+ * Synthesizes the output string from a MicroProps and DecimalQuantity.
+ * This method formats only the main number, not affixes.
+ */
+ static int32_t writeNumber(const MicroProps& micros, DecimalQuantity& quantity,
+ FormattedStringBuilder& string, int32_t index, UErrorCode& status);
+
+ /**
+ * Adds the affixes. Intended to be called immediately after formatNumber.
+ */
+ static int32_t writeAffixes(const MicroProps& micros, FormattedStringBuilder& string, int32_t start,
+ int32_t end, UErrorCode& status);
+
+ private:
+ // Head of the MicroPropsGenerator linked list:
+ const MicroPropsGenerator *fMicroPropsGenerator = nullptr;
+
+ // Tail of the list:
+ MicroProps fMicros;
+
+ // Other fields possibly used by the number formatting pipeline:
+ // TODO: Convert more of these LocalPointers to value objects to reduce the number of news?
+ LocalPointer<const DecimalFormatSymbols> fSymbols;
+ LocalPointer<const PluralRules> fRules;
+ LocalPointer<const ParsedPatternInfo> fPatternInfo;
+ LocalPointer<const ScientificHandler> fScientificHandler;
+ LocalPointer<MutablePatternModifier> fPatternModifier;
+ LocalPointer<ImmutablePatternModifier> fImmutablePatternModifier;
+ LocalPointer<const LongNameHandler> fLongNameHandler;
+ LocalPointer<const CompactHandler> fCompactHandler;
+
+ // Value objects possibly used by the number formatting pipeline:
+ struct Warehouse {
+ CurrencySymbols fCurrencySymbols;
+ } fWarehouse;
+
+
+ NumberFormatterImpl(const MacroProps &macros, bool safe, UErrorCode &status);
+
+ MicroProps& preProcessUnsafe(DecimalQuantity &inValue, UErrorCode &status);
+
+ int32_t getPrefixSuffixUnsafe(Signum signum, StandardPlural::Form plural,
+ FormattedStringBuilder& 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.
+ */
+ const PluralRules *
+ resolvePluralRules(const PluralRules *rulesPtr, const Locale &locale, UErrorCode &status);
+
+ /**
+ * Synthesizes the MacroProps into a MicroPropsGenerator. All information, including the locale, is encoded into the
+ * MicroPropsGenerator, except for the quantity itself, which is left abstract and must be provided to the returned
+ * MicroPropsGenerator instance.
+ *
+ * @see MicroPropsGenerator
+ * @param macros
+ * The {@link MacroProps} to consume. This method does not mutate the MacroProps instance.
+ * @param safe
+ * If true, the returned MicroPropsGenerator will be thread-safe. If false, the returned value will
+ * <em>not</em> be thread-safe, intended for a single "one-shot" use only. Building the thread-safe
+ * object is more expensive.
+ */
+ const MicroPropsGenerator *
+ macrosToMicroGenerator(const MacroProps &macros, bool safe, UErrorCode &status);
+
+ static int32_t
+ writeIntegerDigits(const MicroProps &micros, DecimalQuantity &quantity, FormattedStringBuilder &string,
+ int32_t index, UErrorCode &status);
+
+ static int32_t
+ writeFractionDigits(const MicroProps &micros, DecimalQuantity &quantity, FormattedStringBuilder &string,
+ int32_t index, UErrorCode &status);
+};
+
+} // namespace impl
+} // namespace number
+U_NAMESPACE_END
+
+
+#endif //__NUMBER_FORMATIMPL_H__
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_grouping.cpp b/contrib/libs/icu/i18n/number_grouping.cpp
index 41f727a458..8854e3e091 100644
--- a/contrib/libs/icu/i18n/number_grouping.cpp
+++ b/contrib/libs/icu/i18n/number_grouping.cpp
@@ -1,109 +1,109 @@
-// © 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
-
-#include "unicode/numberformatter.h"
-#include "number_patternstring.h"
-#include "uresimp.h"
-
-using namespace icu;
-using namespace icu::number;
-using namespace icu::number::impl;
-
-namespace {
-
-int16_t getMinGroupingForLocale(const Locale& locale) {
- // TODO: Cache this?
- UErrorCode localStatus = U_ZERO_ERROR;
- LocalUResourceBundlePointer bundle(ures_open(NULL, locale.getName(), &localStatus));
- int32_t resultLen = 0;
- const char16_t* result = ures_getStringByKeyWithFallback(
- bundle.getAlias(),
- "NumberElements/minimumGroupingDigits",
- &resultLen,
- &localStatus);
- // TODO: Is it safe to assume resultLen == 1? Would locales set minGrouping >= 10?
- if (U_FAILURE(localStatus) || resultLen != 1) {
- return 1;
- }
- return result[0] - u'0';
-}
-
-}
-
-Grouper Grouper::forStrategy(UNumberGroupingStrategy grouping) {
- switch (grouping) {
- case UNUM_GROUPING_OFF:
- return {-1, -1, -2, grouping};
- case UNUM_GROUPING_AUTO:
- return {-2, -2, -2, grouping};
- case UNUM_GROUPING_MIN2:
- return {-2, -2, -3, grouping};
- case UNUM_GROUPING_ON_ALIGNED:
- return {-4, -4, 1, grouping};
- case UNUM_GROUPING_THOUSANDS:
- return {3, 3, 1, grouping};
- default:
- UPRV_UNREACHABLE;
- }
-}
-
-Grouper Grouper::forProperties(const DecimalFormatProperties& properties) {
- if (!properties.groupingUsed) {
- return forStrategy(UNUM_GROUPING_OFF);
- }
- auto grouping1 = static_cast<int16_t>(properties.groupingSize);
- auto grouping2 = static_cast<int16_t>(properties.secondaryGroupingSize);
- auto minGrouping = static_cast<int16_t>(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;
- }
- auto grouping1 = static_cast<int16_t> (patternInfo.positive.groupingSizes & 0xffff);
- auto grouping2 = static_cast<int16_t> ((patternInfo.positive.groupingSizes >> 16) & 0xffff);
- auto grouping3 = static_cast<int16_t> ((patternInfo.positive.groupingSizes >> 32) & 0xffff);
- if (grouping2 == -1) {
- grouping1 = fGrouping1 == -4 ? (short) 3 : (short) -1;
- }
- if (grouping3 == -1) {
- grouping2 = grouping1;
- }
- if (fMinGrouping == -2) {
- fMinGrouping = getMinGroupingForLocale(locale);
- } else if (fMinGrouping == -3) {
- fMinGrouping = static_cast<int16_t>(uprv_max(2, getMinGroupingForLocale(locale)));
- } else {
- // leave fMinGrouping alone
- }
- fGrouping1 = grouping1;
- fGrouping2 = grouping2;
-}
-
-bool Grouper::groupAtPosition(int32_t position, const impl::DecimalQuantity &value) const {
- U_ASSERT(fGrouping1 > -2);
- if (fGrouping1 == -1 || fGrouping1 == 0) {
- // Either -1 or 0 means "no grouping"
- return false;
- }
- position -= fGrouping1;
- return position >= 0 && (position % fGrouping2) == 0
- && value.getUpperDisplayMagnitude() - fGrouping1 + 1 >= fMinGrouping;
-}
-
-int16_t Grouper::getPrimary() const {
- return fGrouping1;
-}
-
-int16_t Grouper::getSecondary() const {
- return fGrouping2;
-}
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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
+
+#include "unicode/numberformatter.h"
+#include "number_patternstring.h"
+#include "uresimp.h"
+
+using namespace icu;
+using namespace icu::number;
+using namespace icu::number::impl;
+
+namespace {
+
+int16_t getMinGroupingForLocale(const Locale& locale) {
+ // TODO: Cache this?
+ UErrorCode localStatus = U_ZERO_ERROR;
+ LocalUResourceBundlePointer bundle(ures_open(NULL, locale.getName(), &localStatus));
+ int32_t resultLen = 0;
+ const char16_t* result = ures_getStringByKeyWithFallback(
+ bundle.getAlias(),
+ "NumberElements/minimumGroupingDigits",
+ &resultLen,
+ &localStatus);
+ // TODO: Is it safe to assume resultLen == 1? Would locales set minGrouping >= 10?
+ if (U_FAILURE(localStatus) || resultLen != 1) {
+ return 1;
+ }
+ return result[0] - u'0';
+}
+
+}
+
+Grouper Grouper::forStrategy(UNumberGroupingStrategy grouping) {
+ switch (grouping) {
+ case UNUM_GROUPING_OFF:
+ return {-1, -1, -2, grouping};
+ case UNUM_GROUPING_AUTO:
+ return {-2, -2, -2, grouping};
+ case UNUM_GROUPING_MIN2:
+ return {-2, -2, -3, grouping};
+ case UNUM_GROUPING_ON_ALIGNED:
+ return {-4, -4, 1, grouping};
+ case UNUM_GROUPING_THOUSANDS:
+ return {3, 3, 1, grouping};
+ default:
+ UPRV_UNREACHABLE;
+ }
+}
+
+Grouper Grouper::forProperties(const DecimalFormatProperties& properties) {
+ if (!properties.groupingUsed) {
+ return forStrategy(UNUM_GROUPING_OFF);
+ }
+ auto grouping1 = static_cast<int16_t>(properties.groupingSize);
+ auto grouping2 = static_cast<int16_t>(properties.secondaryGroupingSize);
+ auto minGrouping = static_cast<int16_t>(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;
+ }
+ auto grouping1 = static_cast<int16_t> (patternInfo.positive.groupingSizes & 0xffff);
+ auto grouping2 = static_cast<int16_t> ((patternInfo.positive.groupingSizes >> 16) & 0xffff);
+ auto grouping3 = static_cast<int16_t> ((patternInfo.positive.groupingSizes >> 32) & 0xffff);
+ if (grouping2 == -1) {
+ grouping1 = fGrouping1 == -4 ? (short) 3 : (short) -1;
+ }
+ if (grouping3 == -1) {
+ grouping2 = grouping1;
+ }
+ if (fMinGrouping == -2) {
+ fMinGrouping = getMinGroupingForLocale(locale);
+ } else if (fMinGrouping == -3) {
+ fMinGrouping = static_cast<int16_t>(uprv_max(2, getMinGroupingForLocale(locale)));
+ } else {
+ // leave fMinGrouping alone
+ }
+ fGrouping1 = grouping1;
+ fGrouping2 = grouping2;
+}
+
+bool Grouper::groupAtPosition(int32_t position, const impl::DecimalQuantity &value) const {
+ U_ASSERT(fGrouping1 > -2);
+ if (fGrouping1 == -1 || fGrouping1 == 0) {
+ // Either -1 or 0 means "no grouping"
+ return false;
+ }
+ position -= fGrouping1;
+ return position >= 0 && (position % fGrouping2) == 0
+ && 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/contrib/libs/icu/i18n/number_integerwidth.cpp b/contrib/libs/icu/i18n/number_integerwidth.cpp
index d62aef444d..1efb63de75 100644
--- a/contrib/libs/icu/i18n/number_integerwidth.cpp
+++ b/contrib/libs/icu/i18n/number_integerwidth.cpp
@@ -1,68 +1,68 @@
-// © 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
-
-#include "unicode/numberformatter.h"
-#include "number_types.h"
-#include "number_decimalquantity.h"
-
-using namespace icu;
-using namespace icu::number;
-using namespace icu::number::impl;
-
-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<digits_t>(minInt), -1, false};
- } else {
- return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
- }
-}
-
-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<digits_t>(maxInt), false};
- } else if (maxInt == -1) {
- return {minInt, -1, false};
- } else {
- return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
- }
-}
-
-void IntegerWidth::apply(impl::DecimalQuantity& quantity, UErrorCode& status) const {
- if (fHasError) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- } else if (fUnion.minMaxInt.fMaxInt == -1) {
- quantity.setMinInteger(fUnion.minMaxInt.fMinInt);
- } else {
- // Enforce the backwards-compatibility feature "FormatFailIfMoreThanMaxDigits"
- if (fUnion.minMaxInt.fFormatFailIfMoreThanMaxDigits &&
- fUnion.minMaxInt.fMaxInt < quantity.getMagnitude()) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- }
- quantity.setMinInteger(fUnion.minMaxInt.fMinInt);
- quantity.applyMaxInteger(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 */
+// © 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
+
+#include "unicode/numberformatter.h"
+#include "number_types.h"
+#include "number_decimalquantity.h"
+
+using namespace icu;
+using namespace icu::number;
+using namespace icu::number::impl;
+
+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<digits_t>(minInt), -1, false};
+ } else {
+ return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
+ }
+}
+
+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<digits_t>(maxInt), false};
+ } else if (maxInt == -1) {
+ return {minInt, -1, false};
+ } else {
+ return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
+ }
+}
+
+void IntegerWidth::apply(impl::DecimalQuantity& quantity, UErrorCode& status) const {
+ if (fHasError) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ } else if (fUnion.minMaxInt.fMaxInt == -1) {
+ quantity.setMinInteger(fUnion.minMaxInt.fMinInt);
+ } else {
+ // Enforce the backwards-compatibility feature "FormatFailIfMoreThanMaxDigits"
+ if (fUnion.minMaxInt.fFormatFailIfMoreThanMaxDigits &&
+ fUnion.minMaxInt.fMaxInt < quantity.getMagnitude()) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ quantity.setMinInteger(fUnion.minMaxInt.fMinInt);
+ quantity.applyMaxInteger(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/contrib/libs/icu/i18n/number_longnames.cpp b/contrib/libs/icu/i18n/number_longnames.cpp
index bb32d0381a..135aa3f7d9 100644
--- a/contrib/libs/icu/i18n/number_longnames.cpp
+++ b/contrib/libs/icu/i18n/number_longnames.cpp
@@ -1,350 +1,350 @@
-// © 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
-
-#include "unicode/simpleformatter.h"
-#include "unicode/ures.h"
-#include "ureslocs.h"
-#include "charstr.h"
-#include "uresimp.h"
-#include "number_longnames.h"
-#include "number_microprops.h"
-#include <algorithm>
-#include "cstring.h"
-#include "util.h"
-
-using namespace icu;
-using namespace icu::number;
-using namespace icu::number::impl;
-
-namespace {
-
-constexpr int32_t DNAM_INDEX = StandardPlural::Form::COUNT;
-constexpr int32_t PER_INDEX = StandardPlural::Form::COUNT + 1;
-constexpr int32_t ARRAY_LENGTH = StandardPlural::Form::COUNT + 2;
-
-static int32_t getIndex(const char* pluralKeyword, UErrorCode& status) {
- // pluralKeyword can also be "dnam" or "per"
- if (uprv_strcmp(pluralKeyword, "dnam") == 0) {
- return DNAM_INDEX;
- } else if (uprv_strcmp(pluralKeyword, "per") == 0) {
- return PER_INDEX;
- } else {
- StandardPlural::Form plural = StandardPlural::fromString(pluralKeyword, status);
- return plural;
- }
-}
-
-static UnicodeString getWithPlural(
- const UnicodeString* strings,
- StandardPlural::Form plural,
- UErrorCode& status) {
- UnicodeString result = strings[plural];
- if (result.isBogus()) {
- result = strings[StandardPlural::Form::OTHER];
- }
- if (result.isBogus()) {
- // There should always be data in the "other" plural variant.
- status = U_INTERNAL_PROGRAM_ERROR;
- }
- return result;
-}
-
-
-//////////////////////////
-/// BEGIN DATA LOADING ///
-//////////////////////////
-
-class PluralTableSink : public ResourceSink {
- public:
- explicit PluralTableSink(UnicodeString *outArray) : outArray(outArray) {
- // Initialize the array to bogus strings.
- for (int32_t i = 0; i < ARRAY_LENGTH; i++) {
- outArray[i].setToBogus();
- }
- }
-
- void put(const char *key, ResourceValue &value, UBool /*noFallback*/, UErrorCode &status) U_OVERRIDE {
- ResourceTable pluralsTable = value.getTable(status);
- if (U_FAILURE(status)) { return; }
- for (int32_t i = 0; pluralsTable.getKeyAndValue(i, key, value); ++i) {
- int32_t index = getIndex(key, status);
- if (U_FAILURE(status)) { return; }
- if (!outArray[index].isBogus()) {
- continue;
- }
- outArray[index] = value.getUnicodeString(status);
- if (U_FAILURE(status)) { return; }
- }
- }
-
- private:
- UnicodeString *outArray;
-};
-
-// NOTE: outArray MUST have room for all StandardPlural values. No bounds checking is performed.
-
-void getMeasureData(const Locale &locale, const MeasureUnit &unit, const UNumberUnitWidth &width,
- UnicodeString *outArray, UErrorCode &status) {
- PluralTableSink sink(outArray);
- LocalUResourceBundlePointer unitsBundle(ures_open(U_ICUDATA_UNIT, locale.getName(), &status));
- if (U_FAILURE(status)) { return; }
-
- // Map duration-year-person, duration-week-person, etc. to duration-year, duration-week, ...
- // TODO(ICU-20400): Get duration-*-person data properly with aliases.
- StringPiece subtypeForResource;
- int32_t subtypeLen = static_cast<int32_t>(uprv_strlen(unit.getSubtype()));
- if (subtypeLen > 7 && uprv_strcmp(unit.getSubtype() + subtypeLen - 7, "-person") == 0) {
- subtypeForResource = {unit.getSubtype(), subtypeLen - 7};
- } else {
- subtypeForResource = unit.getSubtype();
- }
-
- CharString key;
- key.append("units", status);
- if (width == UNUM_UNIT_WIDTH_NARROW) {
- key.append("Narrow", status);
- } else if (width == UNUM_UNIT_WIDTH_SHORT) {
- key.append("Short", status);
- }
- key.append("/", status);
- key.append(unit.getType(), status);
- key.append("/", status);
- key.append(subtypeForResource, status);
-
- UErrorCode localStatus = U_ZERO_ERROR;
- ures_getAllItemsWithFallback(unitsBundle.getAlias(), key.data(), sink, localStatus);
- if (width == UNUM_UNIT_WIDTH_SHORT) {
- if (U_FAILURE(localStatus)) {
- status = localStatus;
- }
- return;
- }
-
- // TODO(ICU-13353): The fallback to short does not work in ICU4C.
- // Manually fall back to short (this is done automatically in Java).
- key.clear();
- key.append("unitsShort/", status);
- key.append(unit.getType(), status);
- key.append("/", status);
- key.append(subtypeForResource, status);
- ures_getAllItemsWithFallback(unitsBundle.getAlias(), key.data(), sink, status);
-}
-
-void getCurrencyLongNameData(const Locale &locale, const CurrencyUnit &currency, UnicodeString *outArray,
- UErrorCode &status) {
- // In ICU4J, this method gets a CurrencyData from CurrencyData.provider.
- // TODO(ICU4J): Implement this without going through CurrencyData, like in ICU4C?
- PluralTableSink sink(outArray);
- LocalUResourceBundlePointer unitsBundle(ures_open(U_ICUDATA_CURR, locale.getName(), &status));
- if (U_FAILURE(status)) { return; }
- ures_getAllItemsWithFallback(unitsBundle.getAlias(), "CurrencyUnitPatterns", sink, status);
- if (U_FAILURE(status)) { return; }
- for (int32_t i = 0; i < StandardPlural::Form::COUNT; i++) {
- UnicodeString &pattern = outArray[i];
- if (pattern.isBogus()) {
- continue;
- }
- int32_t longNameLen = 0;
- const char16_t *longName = ucurr_getPluralName(
- currency.getISOCurrency(),
- locale.getName(),
- nullptr /* isChoiceFormat */,
- StandardPlural::getKeyword(static_cast<StandardPlural::Form>(i)),
- &longNameLen,
- &status);
- // Example pattern from data: "{0} {1}"
- // Example output after find-and-replace: "{0} US dollars"
- pattern.findAndReplace(UnicodeString(u"{1}"), UnicodeString(longName, longNameLen));
- }
-}
-
-UnicodeString getPerUnitFormat(const Locale& locale, const UNumberUnitWidth &width, UErrorCode& status) {
- LocalUResourceBundlePointer unitsBundle(ures_open(U_ICUDATA_UNIT, locale.getName(), &status));
- if (U_FAILURE(status)) { return {}; }
- CharString key;
- key.append("units", status);
- if (width == UNUM_UNIT_WIDTH_NARROW) {
- key.append("Narrow", status);
- } else if (width == UNUM_UNIT_WIDTH_SHORT) {
- key.append("Short", status);
- }
- key.append("/compound/per", status);
- int32_t len = 0;
- const UChar* ptr = ures_getStringByKeyWithFallback(unitsBundle.getAlias(), key.data(), &len, &status);
- return UnicodeString(ptr, len);
-}
-
-////////////////////////
-/// END DATA LOADING ///
-////////////////////////
-
-} // namespace
-
-LongNameHandler*
-LongNameHandler::forMeasureUnit(const Locale &loc, const MeasureUnit &unitRef, const MeasureUnit &perUnit,
- const UNumberUnitWidth &width, const PluralRules *rules,
- const MicroPropsGenerator *parent, UErrorCode &status) {
- if (uprv_strlen(unitRef.getType()) == 0 || uprv_strlen(perUnit.getType()) == 0) {
- // TODO(ICU-20941): Unsanctioned unit. Not yet fully supported. Set an error code.
- status = U_UNSUPPORTED_ERROR;
- return nullptr;
- }
-
- MeasureUnit unit = unitRef;
- if (uprv_strcmp(perUnit.getType(), "none") != 0) {
- // Compound unit: first try to simplify (e.g., meters per second is its own unit).
- bool isResolved = false;
- MeasureUnit resolved = MeasureUnit::resolveUnitPerUnit(unit, perUnit, &isResolved);
- if (isResolved) {
- unit = resolved;
- } else {
- // No simplified form is available.
- return forCompoundUnit(loc, unit, perUnit, width, rules, parent, status);
- }
- }
-
- auto* result = new LongNameHandler(rules, parent);
- if (result == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
- UnicodeString simpleFormats[ARRAY_LENGTH];
- getMeasureData(loc, unit, width, simpleFormats, status);
- if (U_FAILURE(status)) { return result; }
- result->simpleFormatsToModifiers(simpleFormats, {UFIELD_CATEGORY_NUMBER, UNUM_MEASURE_UNIT_FIELD}, status);
- return result;
-}
-
-LongNameHandler*
-LongNameHandler::forCompoundUnit(const Locale &loc, const MeasureUnit &unit, const MeasureUnit &perUnit,
- const UNumberUnitWidth &width, const PluralRules *rules,
- const MicroPropsGenerator *parent, UErrorCode &status) {
- auto* result = new LongNameHandler(rules, parent);
- if (result == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
- UnicodeString primaryData[ARRAY_LENGTH];
- getMeasureData(loc, unit, width, primaryData, status);
- if (U_FAILURE(status)) { return result; }
- UnicodeString secondaryData[ARRAY_LENGTH];
- getMeasureData(loc, perUnit, width, secondaryData, status);
- if (U_FAILURE(status)) { return result; }
-
- UnicodeString perUnitFormat;
- if (!secondaryData[PER_INDEX].isBogus()) {
- perUnitFormat = secondaryData[PER_INDEX];
- } else {
- UnicodeString rawPerUnitFormat = getPerUnitFormat(loc, width, status);
- if (U_FAILURE(status)) { return result; }
- // rawPerUnitFormat is something like "{0}/{1}"; we need to substitute in the secondary unit.
- SimpleFormatter compiled(rawPerUnitFormat, 2, 2, status);
- if (U_FAILURE(status)) { return result; }
- UnicodeString secondaryFormat = getWithPlural(secondaryData, StandardPlural::Form::ONE, status);
- if (U_FAILURE(status)) { return result; }
- // Some "one" pattern may not contain "{0}". For example in "ar" or "ne" locale.
- SimpleFormatter secondaryCompiled(secondaryFormat, 0, 1, status);
- if (U_FAILURE(status)) { return result; }
- UnicodeString secondaryString = secondaryCompiled.getTextWithNoArguments().trim();
- // TODO: Why does UnicodeString need to be explicit in the following line?
- compiled.format(UnicodeString(u"{0}"), secondaryString, perUnitFormat, status);
- if (U_FAILURE(status)) { return result; }
- }
- result->multiSimpleFormatsToModifiers(primaryData, perUnitFormat, {UFIELD_CATEGORY_NUMBER, UNUM_MEASURE_UNIT_FIELD}, status);
- return result;
-}
-
-UnicodeString LongNameHandler::getUnitDisplayName(
- const Locale& loc,
- const MeasureUnit& unit,
- UNumberUnitWidth width,
- UErrorCode& status) {
- if (U_FAILURE(status)) {
- return ICU_Utility::makeBogusString();
- }
- UnicodeString simpleFormats[ARRAY_LENGTH];
- getMeasureData(loc, unit, width, simpleFormats, status);
- return simpleFormats[DNAM_INDEX];
-}
-
-UnicodeString LongNameHandler::getUnitPattern(
- const Locale& loc,
- const MeasureUnit& unit,
- UNumberUnitWidth width,
- StandardPlural::Form pluralForm,
- UErrorCode& status) {
- if (U_FAILURE(status)) {
- return ICU_Utility::makeBogusString();
- }
- UnicodeString simpleFormats[ARRAY_LENGTH];
- getMeasureData(loc, unit, width, simpleFormats, status);
- // The above already handles fallback from other widths to short
- if (U_FAILURE(status)) {
- return ICU_Utility::makeBogusString();
- }
- // Now handle fallback from other plural forms to OTHER
- return (!(simpleFormats[pluralForm]).isBogus())? simpleFormats[pluralForm]:
- simpleFormats[StandardPlural::Form::OTHER];
-}
-
-LongNameHandler* LongNameHandler::forCurrencyLongNames(const Locale &loc, const CurrencyUnit &currency,
- const PluralRules *rules,
- const MicroPropsGenerator *parent,
- UErrorCode &status) {
- auto* result = new LongNameHandler(rules, parent);
- if (result == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
- UnicodeString simpleFormats[ARRAY_LENGTH];
- getCurrencyLongNameData(loc, currency, simpleFormats, status);
- if (U_FAILURE(status)) { return nullptr; }
- result->simpleFormatsToModifiers(simpleFormats, {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD}, status);
- return result;
-}
-
-void LongNameHandler::simpleFormatsToModifiers(const UnicodeString *simpleFormats, Field field,
- UErrorCode &status) {
- for (int32_t i = 0; i < StandardPlural::Form::COUNT; i++) {
- StandardPlural::Form plural = static_cast<StandardPlural::Form>(i);
- UnicodeString simpleFormat = getWithPlural(simpleFormats, plural, status);
- if (U_FAILURE(status)) { return; }
- SimpleFormatter compiledFormatter(simpleFormat, 0, 1, status);
- if (U_FAILURE(status)) { return; }
- fModifiers[i] = SimpleModifier(compiledFormatter, field, false, {this, SIGNUM_POS_ZERO, plural});
- }
-}
-
-void LongNameHandler::multiSimpleFormatsToModifiers(const UnicodeString *leadFormats, UnicodeString trailFormat,
- Field field, UErrorCode &status) {
- SimpleFormatter trailCompiled(trailFormat, 1, 1, status);
- if (U_FAILURE(status)) { return; }
- for (int32_t i = 0; i < StandardPlural::Form::COUNT; i++) {
- StandardPlural::Form plural = static_cast<StandardPlural::Form>(i);
- UnicodeString leadFormat = getWithPlural(leadFormats, plural, status);
- if (U_FAILURE(status)) { return; }
- UnicodeString compoundFormat;
- trailCompiled.format(leadFormat, compoundFormat, status);
- if (U_FAILURE(status)) { return; }
- SimpleFormatter compoundCompiled(compoundFormat, 0, 1, status);
- if (U_FAILURE(status)) { return; }
- fModifiers[i] = SimpleModifier(compoundCompiled, field, false, {this, SIGNUM_POS_ZERO, plural});
- }
-}
-
-void LongNameHandler::processQuantity(DecimalQuantity &quantity, MicroProps &micros,
- UErrorCode &status) const {
- parent->processQuantity(quantity, micros, status);
- StandardPlural::Form pluralForm = utils::getPluralSafe(micros.rounder, rules, quantity, status);
- micros.modOuter = &fModifiers[pluralForm];
-}
-
-const Modifier* LongNameHandler::getModifier(Signum /*signum*/, StandardPlural::Form plural) const {
- return &fModifiers[plural];
-}
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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
+
+#include "unicode/simpleformatter.h"
+#include "unicode/ures.h"
+#include "ureslocs.h"
+#include "charstr.h"
+#include "uresimp.h"
+#include "number_longnames.h"
+#include "number_microprops.h"
+#include <algorithm>
+#include "cstring.h"
+#include "util.h"
+
+using namespace icu;
+using namespace icu::number;
+using namespace icu::number::impl;
+
+namespace {
+
+constexpr int32_t DNAM_INDEX = StandardPlural::Form::COUNT;
+constexpr int32_t PER_INDEX = StandardPlural::Form::COUNT + 1;
+constexpr int32_t ARRAY_LENGTH = StandardPlural::Form::COUNT + 2;
+
+static int32_t getIndex(const char* pluralKeyword, UErrorCode& status) {
+ // pluralKeyword can also be "dnam" or "per"
+ if (uprv_strcmp(pluralKeyword, "dnam") == 0) {
+ return DNAM_INDEX;
+ } else if (uprv_strcmp(pluralKeyword, "per") == 0) {
+ return PER_INDEX;
+ } else {
+ StandardPlural::Form plural = StandardPlural::fromString(pluralKeyword, status);
+ return plural;
+ }
+}
+
+static UnicodeString getWithPlural(
+ const UnicodeString* strings,
+ StandardPlural::Form plural,
+ UErrorCode& status) {
+ UnicodeString result = strings[plural];
+ if (result.isBogus()) {
+ result = strings[StandardPlural::Form::OTHER];
+ }
+ if (result.isBogus()) {
+ // There should always be data in the "other" plural variant.
+ status = U_INTERNAL_PROGRAM_ERROR;
+ }
+ return result;
+}
+
+
+//////////////////////////
+/// BEGIN DATA LOADING ///
+//////////////////////////
+
+class PluralTableSink : public ResourceSink {
+ public:
+ explicit PluralTableSink(UnicodeString *outArray) : outArray(outArray) {
+ // Initialize the array to bogus strings.
+ for (int32_t i = 0; i < ARRAY_LENGTH; i++) {
+ outArray[i].setToBogus();
+ }
+ }
+
+ void put(const char *key, ResourceValue &value, UBool /*noFallback*/, UErrorCode &status) U_OVERRIDE {
+ ResourceTable pluralsTable = value.getTable(status);
+ if (U_FAILURE(status)) { return; }
+ for (int32_t i = 0; pluralsTable.getKeyAndValue(i, key, value); ++i) {
+ int32_t index = getIndex(key, status);
+ if (U_FAILURE(status)) { return; }
+ if (!outArray[index].isBogus()) {
+ continue;
+ }
+ outArray[index] = value.getUnicodeString(status);
+ if (U_FAILURE(status)) { return; }
+ }
+ }
+
+ private:
+ UnicodeString *outArray;
+};
+
+// NOTE: outArray MUST have room for all StandardPlural values. No bounds checking is performed.
+
+void getMeasureData(const Locale &locale, const MeasureUnit &unit, const UNumberUnitWidth &width,
+ UnicodeString *outArray, UErrorCode &status) {
+ PluralTableSink sink(outArray);
+ LocalUResourceBundlePointer unitsBundle(ures_open(U_ICUDATA_UNIT, locale.getName(), &status));
+ if (U_FAILURE(status)) { return; }
+
+ // Map duration-year-person, duration-week-person, etc. to duration-year, duration-week, ...
+ // TODO(ICU-20400): Get duration-*-person data properly with aliases.
+ StringPiece subtypeForResource;
+ int32_t subtypeLen = static_cast<int32_t>(uprv_strlen(unit.getSubtype()));
+ if (subtypeLen > 7 && uprv_strcmp(unit.getSubtype() + subtypeLen - 7, "-person") == 0) {
+ subtypeForResource = {unit.getSubtype(), subtypeLen - 7};
+ } else {
+ subtypeForResource = unit.getSubtype();
+ }
+
+ CharString key;
+ key.append("units", status);
+ if (width == UNUM_UNIT_WIDTH_NARROW) {
+ key.append("Narrow", status);
+ } else if (width == UNUM_UNIT_WIDTH_SHORT) {
+ key.append("Short", status);
+ }
+ key.append("/", status);
+ key.append(unit.getType(), status);
+ key.append("/", status);
+ key.append(subtypeForResource, status);
+
+ UErrorCode localStatus = U_ZERO_ERROR;
+ ures_getAllItemsWithFallback(unitsBundle.getAlias(), key.data(), sink, localStatus);
+ if (width == UNUM_UNIT_WIDTH_SHORT) {
+ if (U_FAILURE(localStatus)) {
+ status = localStatus;
+ }
+ return;
+ }
+
+ // TODO(ICU-13353): The fallback to short does not work in ICU4C.
+ // Manually fall back to short (this is done automatically in Java).
+ key.clear();
+ key.append("unitsShort/", status);
+ key.append(unit.getType(), status);
+ key.append("/", status);
+ key.append(subtypeForResource, status);
+ ures_getAllItemsWithFallback(unitsBundle.getAlias(), key.data(), sink, status);
+}
+
+void getCurrencyLongNameData(const Locale &locale, const CurrencyUnit &currency, UnicodeString *outArray,
+ UErrorCode &status) {
+ // In ICU4J, this method gets a CurrencyData from CurrencyData.provider.
+ // TODO(ICU4J): Implement this without going through CurrencyData, like in ICU4C?
+ PluralTableSink sink(outArray);
+ LocalUResourceBundlePointer unitsBundle(ures_open(U_ICUDATA_CURR, locale.getName(), &status));
+ if (U_FAILURE(status)) { return; }
+ ures_getAllItemsWithFallback(unitsBundle.getAlias(), "CurrencyUnitPatterns", sink, status);
+ if (U_FAILURE(status)) { return; }
+ for (int32_t i = 0; i < StandardPlural::Form::COUNT; i++) {
+ UnicodeString &pattern = outArray[i];
+ if (pattern.isBogus()) {
+ continue;
+ }
+ int32_t longNameLen = 0;
+ const char16_t *longName = ucurr_getPluralName(
+ currency.getISOCurrency(),
+ locale.getName(),
+ nullptr /* isChoiceFormat */,
+ StandardPlural::getKeyword(static_cast<StandardPlural::Form>(i)),
+ &longNameLen,
+ &status);
+ // Example pattern from data: "{0} {1}"
+ // Example output after find-and-replace: "{0} US dollars"
+ pattern.findAndReplace(UnicodeString(u"{1}"), UnicodeString(longName, longNameLen));
+ }
+}
+
+UnicodeString getPerUnitFormat(const Locale& locale, const UNumberUnitWidth &width, UErrorCode& status) {
+ LocalUResourceBundlePointer unitsBundle(ures_open(U_ICUDATA_UNIT, locale.getName(), &status));
+ if (U_FAILURE(status)) { return {}; }
+ CharString key;
+ key.append("units", status);
+ if (width == UNUM_UNIT_WIDTH_NARROW) {
+ key.append("Narrow", status);
+ } else if (width == UNUM_UNIT_WIDTH_SHORT) {
+ key.append("Short", status);
+ }
+ key.append("/compound/per", status);
+ int32_t len = 0;
+ const UChar* ptr = ures_getStringByKeyWithFallback(unitsBundle.getAlias(), key.data(), &len, &status);
+ return UnicodeString(ptr, len);
+}
+
+////////////////////////
+/// END DATA LOADING ///
+////////////////////////
+
+} // namespace
+
+LongNameHandler*
+LongNameHandler::forMeasureUnit(const Locale &loc, const MeasureUnit &unitRef, const MeasureUnit &perUnit,
+ const UNumberUnitWidth &width, const PluralRules *rules,
+ const MicroPropsGenerator *parent, UErrorCode &status) {
+ if (uprv_strlen(unitRef.getType()) == 0 || uprv_strlen(perUnit.getType()) == 0) {
+ // TODO(ICU-20941): Unsanctioned unit. Not yet fully supported. Set an error code.
+ status = U_UNSUPPORTED_ERROR;
+ return nullptr;
+ }
+
+ MeasureUnit unit = unitRef;
+ if (uprv_strcmp(perUnit.getType(), "none") != 0) {
+ // Compound unit: first try to simplify (e.g., meters per second is its own unit).
+ bool isResolved = false;
+ MeasureUnit resolved = MeasureUnit::resolveUnitPerUnit(unit, perUnit, &isResolved);
+ if (isResolved) {
+ unit = resolved;
+ } else {
+ // No simplified form is available.
+ return forCompoundUnit(loc, unit, perUnit, width, rules, parent, status);
+ }
+ }
+
+ auto* result = new LongNameHandler(rules, parent);
+ if (result == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+ UnicodeString simpleFormats[ARRAY_LENGTH];
+ getMeasureData(loc, unit, width, simpleFormats, status);
+ if (U_FAILURE(status)) { return result; }
+ result->simpleFormatsToModifiers(simpleFormats, {UFIELD_CATEGORY_NUMBER, UNUM_MEASURE_UNIT_FIELD}, status);
+ return result;
+}
+
+LongNameHandler*
+LongNameHandler::forCompoundUnit(const Locale &loc, const MeasureUnit &unit, const MeasureUnit &perUnit,
+ const UNumberUnitWidth &width, const PluralRules *rules,
+ const MicroPropsGenerator *parent, UErrorCode &status) {
+ auto* result = new LongNameHandler(rules, parent);
+ if (result == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+ UnicodeString primaryData[ARRAY_LENGTH];
+ getMeasureData(loc, unit, width, primaryData, status);
+ if (U_FAILURE(status)) { return result; }
+ UnicodeString secondaryData[ARRAY_LENGTH];
+ getMeasureData(loc, perUnit, width, secondaryData, status);
+ if (U_FAILURE(status)) { return result; }
+
+ UnicodeString perUnitFormat;
+ if (!secondaryData[PER_INDEX].isBogus()) {
+ perUnitFormat = secondaryData[PER_INDEX];
+ } else {
+ UnicodeString rawPerUnitFormat = getPerUnitFormat(loc, width, status);
+ if (U_FAILURE(status)) { return result; }
+ // rawPerUnitFormat is something like "{0}/{1}"; we need to substitute in the secondary unit.
+ SimpleFormatter compiled(rawPerUnitFormat, 2, 2, status);
+ if (U_FAILURE(status)) { return result; }
+ UnicodeString secondaryFormat = getWithPlural(secondaryData, StandardPlural::Form::ONE, status);
+ if (U_FAILURE(status)) { return result; }
+ // Some "one" pattern may not contain "{0}". For example in "ar" or "ne" locale.
+ SimpleFormatter secondaryCompiled(secondaryFormat, 0, 1, status);
+ if (U_FAILURE(status)) { return result; }
+ UnicodeString secondaryString = secondaryCompiled.getTextWithNoArguments().trim();
+ // TODO: Why does UnicodeString need to be explicit in the following line?
+ compiled.format(UnicodeString(u"{0}"), secondaryString, perUnitFormat, status);
+ if (U_FAILURE(status)) { return result; }
+ }
+ result->multiSimpleFormatsToModifiers(primaryData, perUnitFormat, {UFIELD_CATEGORY_NUMBER, UNUM_MEASURE_UNIT_FIELD}, status);
+ return result;
+}
+
+UnicodeString LongNameHandler::getUnitDisplayName(
+ const Locale& loc,
+ const MeasureUnit& unit,
+ UNumberUnitWidth width,
+ UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return ICU_Utility::makeBogusString();
+ }
+ UnicodeString simpleFormats[ARRAY_LENGTH];
+ getMeasureData(loc, unit, width, simpleFormats, status);
+ return simpleFormats[DNAM_INDEX];
+}
+
+UnicodeString LongNameHandler::getUnitPattern(
+ const Locale& loc,
+ const MeasureUnit& unit,
+ UNumberUnitWidth width,
+ StandardPlural::Form pluralForm,
+ UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return ICU_Utility::makeBogusString();
+ }
+ UnicodeString simpleFormats[ARRAY_LENGTH];
+ getMeasureData(loc, unit, width, simpleFormats, status);
+ // The above already handles fallback from other widths to short
+ if (U_FAILURE(status)) {
+ return ICU_Utility::makeBogusString();
+ }
+ // Now handle fallback from other plural forms to OTHER
+ return (!(simpleFormats[pluralForm]).isBogus())? simpleFormats[pluralForm]:
+ simpleFormats[StandardPlural::Form::OTHER];
+}
+
+LongNameHandler* LongNameHandler::forCurrencyLongNames(const Locale &loc, const CurrencyUnit &currency,
+ const PluralRules *rules,
+ const MicroPropsGenerator *parent,
+ UErrorCode &status) {
+ auto* result = new LongNameHandler(rules, parent);
+ if (result == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+ UnicodeString simpleFormats[ARRAY_LENGTH];
+ getCurrencyLongNameData(loc, currency, simpleFormats, status);
+ if (U_FAILURE(status)) { return nullptr; }
+ result->simpleFormatsToModifiers(simpleFormats, {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD}, status);
+ return result;
+}
+
+void LongNameHandler::simpleFormatsToModifiers(const UnicodeString *simpleFormats, Field field,
+ UErrorCode &status) {
+ for (int32_t i = 0; i < StandardPlural::Form::COUNT; i++) {
+ StandardPlural::Form plural = static_cast<StandardPlural::Form>(i);
+ UnicodeString simpleFormat = getWithPlural(simpleFormats, plural, status);
+ if (U_FAILURE(status)) { return; }
+ SimpleFormatter compiledFormatter(simpleFormat, 0, 1, status);
+ if (U_FAILURE(status)) { return; }
+ fModifiers[i] = SimpleModifier(compiledFormatter, field, false, {this, SIGNUM_POS_ZERO, plural});
+ }
+}
+
+void LongNameHandler::multiSimpleFormatsToModifiers(const UnicodeString *leadFormats, UnicodeString trailFormat,
+ Field field, UErrorCode &status) {
+ SimpleFormatter trailCompiled(trailFormat, 1, 1, status);
+ if (U_FAILURE(status)) { return; }
+ for (int32_t i = 0; i < StandardPlural::Form::COUNT; i++) {
+ StandardPlural::Form plural = static_cast<StandardPlural::Form>(i);
+ UnicodeString leadFormat = getWithPlural(leadFormats, plural, status);
+ if (U_FAILURE(status)) { return; }
+ UnicodeString compoundFormat;
+ trailCompiled.format(leadFormat, compoundFormat, status);
+ if (U_FAILURE(status)) { return; }
+ SimpleFormatter compoundCompiled(compoundFormat, 0, 1, status);
+ if (U_FAILURE(status)) { return; }
+ fModifiers[i] = SimpleModifier(compoundCompiled, field, false, {this, SIGNUM_POS_ZERO, plural});
+ }
+}
+
+void LongNameHandler::processQuantity(DecimalQuantity &quantity, MicroProps &micros,
+ UErrorCode &status) const {
+ parent->processQuantity(quantity, micros, status);
+ StandardPlural::Form pluralForm = utils::getPluralSafe(micros.rounder, rules, quantity, status);
+ micros.modOuter = &fModifiers[pluralForm];
+}
+
+const Modifier* LongNameHandler::getModifier(Signum /*signum*/, StandardPlural::Form plural) const {
+ return &fModifiers[plural];
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_longnames.h b/contrib/libs/icu/i18n/number_longnames.h
index a19425aa26..1800b875db 100644
--- a/contrib/libs/icu/i18n/number_longnames.h
+++ b/contrib/libs/icu/i18n/number_longnames.h
@@ -1,70 +1,70 @@
-// © 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_LONGNAMES_H__
-#define __NUMBER_LONGNAMES_H__
-
-#include "unicode/uversion.h"
-#include "number_utils.h"
-#include "number_modifiers.h"
-
-U_NAMESPACE_BEGIN namespace number {
-namespace impl {
-
-class LongNameHandler : public MicroPropsGenerator, public ModifierStore, public UMemory {
- public:
- static UnicodeString getUnitDisplayName(
- const Locale& loc,
- const MeasureUnit& unit,
- UNumberUnitWidth width,
- UErrorCode& status);
-
- static UnicodeString getUnitPattern(
- const Locale& loc,
- const MeasureUnit& unit,
- UNumberUnitWidth width,
- StandardPlural::Form pluralForm,
- UErrorCode& status);
-
- static LongNameHandler*
- forCurrencyLongNames(const Locale &loc, const CurrencyUnit &currency, const PluralRules *rules,
- const MicroPropsGenerator *parent, UErrorCode &status);
-
- static LongNameHandler*
- forMeasureUnit(const Locale &loc, const MeasureUnit &unit, const MeasureUnit &perUnit,
- const UNumberUnitWidth &width, const PluralRules *rules,
- const MicroPropsGenerator *parent, UErrorCode &status);
-
- void
- processQuantity(DecimalQuantity &quantity, MicroProps &micros, UErrorCode &status) const U_OVERRIDE;
-
- const Modifier* getModifier(Signum signum, StandardPlural::Form plural) const U_OVERRIDE;
-
- private:
- SimpleModifier fModifiers[StandardPlural::Form::COUNT];
- const PluralRules *rules;
- const MicroPropsGenerator *parent;
-
- LongNameHandler(const PluralRules *rules, const MicroPropsGenerator *parent)
- : rules(rules), parent(parent) {}
-
- static LongNameHandler*
- forCompoundUnit(const Locale &loc, const MeasureUnit &unit, const MeasureUnit &perUnit,
- const UNumberUnitWidth &width, const PluralRules *rules,
- const MicroPropsGenerator *parent, UErrorCode &status);
-
- void simpleFormatsToModifiers(const UnicodeString *simpleFormats, Field field, UErrorCode &status);
- void multiSimpleFormatsToModifiers(const UnicodeString *leadFormats, UnicodeString trailFormat,
- Field field, UErrorCode &status);
-};
-
-} // namespace impl
-} // namespace number
-U_NAMESPACE_END
-
-#endif //__NUMBER_LONGNAMES_H__
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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_LONGNAMES_H__
+#define __NUMBER_LONGNAMES_H__
+
+#include "unicode/uversion.h"
+#include "number_utils.h"
+#include "number_modifiers.h"
+
+U_NAMESPACE_BEGIN namespace number {
+namespace impl {
+
+class LongNameHandler : public MicroPropsGenerator, public ModifierStore, public UMemory {
+ public:
+ static UnicodeString getUnitDisplayName(
+ const Locale& loc,
+ const MeasureUnit& unit,
+ UNumberUnitWidth width,
+ UErrorCode& status);
+
+ static UnicodeString getUnitPattern(
+ const Locale& loc,
+ const MeasureUnit& unit,
+ UNumberUnitWidth width,
+ StandardPlural::Form pluralForm,
+ UErrorCode& status);
+
+ static LongNameHandler*
+ forCurrencyLongNames(const Locale &loc, const CurrencyUnit &currency, const PluralRules *rules,
+ const MicroPropsGenerator *parent, UErrorCode &status);
+
+ static LongNameHandler*
+ forMeasureUnit(const Locale &loc, const MeasureUnit &unit, const MeasureUnit &perUnit,
+ const UNumberUnitWidth &width, const PluralRules *rules,
+ const MicroPropsGenerator *parent, UErrorCode &status);
+
+ void
+ processQuantity(DecimalQuantity &quantity, MicroProps &micros, UErrorCode &status) const U_OVERRIDE;
+
+ const Modifier* getModifier(Signum signum, StandardPlural::Form plural) const U_OVERRIDE;
+
+ private:
+ SimpleModifier fModifiers[StandardPlural::Form::COUNT];
+ const PluralRules *rules;
+ const MicroPropsGenerator *parent;
+
+ LongNameHandler(const PluralRules *rules, const MicroPropsGenerator *parent)
+ : rules(rules), parent(parent) {}
+
+ static LongNameHandler*
+ forCompoundUnit(const Locale &loc, const MeasureUnit &unit, const MeasureUnit &perUnit,
+ const UNumberUnitWidth &width, const PluralRules *rules,
+ const MicroPropsGenerator *parent, UErrorCode &status);
+
+ void simpleFormatsToModifiers(const UnicodeString *simpleFormats, Field field, UErrorCode &status);
+ void multiSimpleFormatsToModifiers(const UnicodeString *leadFormats, UnicodeString trailFormat,
+ Field field, UErrorCode &status);
+};
+
+} // namespace impl
+} // namespace number
+U_NAMESPACE_END
+
+#endif //__NUMBER_LONGNAMES_H__
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_mapper.cpp b/contrib/libs/icu/i18n/number_mapper.cpp
index ec617438c9..e089f9c372 100644
--- a/contrib/libs/icu/i18n/number_mapper.cpp
+++ b/contrib/libs/icu/i18n/number_mapper.cpp
@@ -1,508 +1,508 @@
-// © 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"
-
-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 //
- /////////////
-
- warehouse.affixProvider.setTo(properties, status);
- macros.affixProvider = &warehouse.affixProvider.get();
-
- ///////////
- // UNITS //
- ///////////
-
- bool useCurrency = (
- !properties.currency.isNull() ||
- !properties.currencyPluralInfo.fPtr.isNull() ||
- !properties.currencyUsage.isNull() ||
- warehouse.affixProvider.get().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
- }
-
- ///////////////////////
- // 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.
- if (minInt == 0 && maxFrac != 0) {
- minFrac = (minFrac < 0 || (minFrac == 0 && maxInt == 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) {
- if (PatternStringUtils::ignoreRoundingIncrement(roundingIncrement, maxFrac)) {
- precision = Precision::constructFraction(minFrac, maxFrac);
- } else {
- 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.fRoundingMode = roundingMode;
- macros.precision = precision;
- }
-
- ///////////////////
- // INTEGER WIDTH //
- ///////////////////
-
- macros.integerWidth = IntegerWidth(
- static_cast<digits_t>(minInt),
- static_cast<digits_t>(maxInt),
- properties.formatFailIfMoreThanMaxDigits);
-
- ///////////////////////
- // GROUPING STRATEGY //
- ///////////////////////
-
- macros.grouper = Grouper::forProperties(properties);
-
- /////////////
- // PADDING //
- /////////////
-
- if (properties.formatWidth > 0) {
- 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<int8_t>(engineering),
- // Enforce minimum integer digits (for patterns like "000.00E0"):
- (engineering == minInt),
- // Minimum exponent digits:
- static_cast<digits_t>(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 maxInt_ = properties.maximumIntegerDigits;
- 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();
- } 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);
- } else {
- int maxSig_ = minInt_ + maxFrac_;
- // Bug #20058: if maxInt_ > minInt_ > 1, then minInt_ should be 1.
- if (maxInt_ > minInt_ && minInt_ > 1) {
- minInt_ = 1;
- }
- int minSig_ = minInt_ + minFrac_;
- // To avoid regression, maxSig is not reset when minInt_ set to 1.
- // TODO: Reset maxSig_ = 1 + minFrac_ to follow the spec.
- macros.precision = Precision::constructSignificant(minSig_, maxSig_);
- }
- macros.precision.fRoundingMode = 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
- || rounding_.fType == Precision::PrecisionType::RND_INCREMENT_ONE
- || rounding_.fType == Precision::PrecisionType::RND_INCREMENT_FIVE) {
- 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& status) {
- 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.
-
- // 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;
- }
-
- // For declaring if this is a currency pattern, we need to look at the
- // original pattern, not at any user-specified overrides.
- isCurrencyPattern = (
- AffixUtils::hasCurrencySymbols(ppp, status) ||
- AffixUtils::hasCurrencySymbols(psp, status) ||
- AffixUtils::hasCurrencySymbols(npp, status) ||
- AffixUtils::hasCurrencySymbols(nsp, status));
-}
-
-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 {
- return (
- (negSuffix != posSuffix) ||
- negPrefix.tempSubString(1) != posPrefix ||
- negPrefix.charAt(0) != u'-'
- );
-}
-
-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 {
- return isCurrencyPattern;
-}
-
-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<StandardPlural::Form>(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 */
+// © 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"
+
+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 //
+ /////////////
+
+ warehouse.affixProvider.setTo(properties, status);
+ macros.affixProvider = &warehouse.affixProvider.get();
+
+ ///////////
+ // UNITS //
+ ///////////
+
+ bool useCurrency = (
+ !properties.currency.isNull() ||
+ !properties.currencyPluralInfo.fPtr.isNull() ||
+ !properties.currencyUsage.isNull() ||
+ warehouse.affixProvider.get().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
+ }
+
+ ///////////////////////
+ // 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.
+ if (minInt == 0 && maxFrac != 0) {
+ minFrac = (minFrac < 0 || (minFrac == 0 && maxInt == 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) {
+ if (PatternStringUtils::ignoreRoundingIncrement(roundingIncrement, maxFrac)) {
+ precision = Precision::constructFraction(minFrac, maxFrac);
+ } else {
+ 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.fRoundingMode = roundingMode;
+ macros.precision = precision;
+ }
+
+ ///////////////////
+ // INTEGER WIDTH //
+ ///////////////////
+
+ macros.integerWidth = IntegerWidth(
+ static_cast<digits_t>(minInt),
+ static_cast<digits_t>(maxInt),
+ properties.formatFailIfMoreThanMaxDigits);
+
+ ///////////////////////
+ // GROUPING STRATEGY //
+ ///////////////////////
+
+ macros.grouper = Grouper::forProperties(properties);
+
+ /////////////
+ // PADDING //
+ /////////////
+
+ if (properties.formatWidth > 0) {
+ 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<int8_t>(engineering),
+ // Enforce minimum integer digits (for patterns like "000.00E0"):
+ (engineering == minInt),
+ // Minimum exponent digits:
+ static_cast<digits_t>(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 maxInt_ = properties.maximumIntegerDigits;
+ 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();
+ } 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);
+ } else {
+ int maxSig_ = minInt_ + maxFrac_;
+ // Bug #20058: if maxInt_ > minInt_ > 1, then minInt_ should be 1.
+ if (maxInt_ > minInt_ && minInt_ > 1) {
+ minInt_ = 1;
+ }
+ int minSig_ = minInt_ + minFrac_;
+ // To avoid regression, maxSig is not reset when minInt_ set to 1.
+ // TODO: Reset maxSig_ = 1 + minFrac_ to follow the spec.
+ macros.precision = Precision::constructSignificant(minSig_, maxSig_);
+ }
+ macros.precision.fRoundingMode = 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
+ || rounding_.fType == Precision::PrecisionType::RND_INCREMENT_ONE
+ || rounding_.fType == Precision::PrecisionType::RND_INCREMENT_FIVE) {
+ 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& status) {
+ 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.
+
+ // 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;
+ }
+
+ // For declaring if this is a currency pattern, we need to look at the
+ // original pattern, not at any user-specified overrides.
+ isCurrencyPattern = (
+ AffixUtils::hasCurrencySymbols(ppp, status) ||
+ AffixUtils::hasCurrencySymbols(psp, status) ||
+ AffixUtils::hasCurrencySymbols(npp, status) ||
+ AffixUtils::hasCurrencySymbols(nsp, status));
+}
+
+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 {
+ return (
+ (negSuffix != posSuffix) ||
+ negPrefix.tempSubString(1) != posPrefix ||
+ negPrefix.charAt(0) != u'-'
+ );
+}
+
+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 {
+ return isCurrencyPattern;
+}
+
+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<StandardPlural::Form>(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/contrib/libs/icu/i18n/number_mapper.h b/contrib/libs/icu/i18n/number_mapper.h
index d18b8b3c43..29801257cb 100644
--- a/contrib/libs/icu/i18n/number_mapper.h
+++ b/contrib/libs/icu/i18n/number_mapper.h
@@ -1,251 +1,251 @@
-// © 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 <atomic>
-#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 AutoAffixPatternProvider;
-class CurrencyPluralInfoAffixProvider;
-
-
-class PropertiesAffixPatternProvider : public AffixPatternProvider, public UMemory {
- public:
- bool isBogus() const {
- return fBogus;
- }
-
- void setToBogus() {
- fBogus = true;
- }
-
- void setTo(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:
- UnicodeString posPrefix;
- UnicodeString posSuffix;
- UnicodeString negPrefix;
- UnicodeString negSuffix;
- bool isCurrencyPattern;
-
- PropertiesAffixPatternProvider() = default; // puts instance in valid but undefined state
-
- const UnicodeString& getStringInternal(int32_t flags) const;
-
- bool fBogus{true};
-
- friend class AutoAffixPatternProvider;
- friend class CurrencyPluralInfoAffixProvider;
-};
-
-
-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];
-
- CurrencyPluralInfoAffixProvider() = default;
-
- bool fBogus{true};
-
- friend class AutoAffixPatternProvider;
-};
-
-
-class AutoAffixPatternProvider {
- public:
- inline AutoAffixPatternProvider() = default;
-
- inline AutoAffixPatternProvider(const DecimalFormatProperties& properties, UErrorCode& status) {
- setTo(properties, status);
- }
-
- inline void setTo(const DecimalFormatProperties& properties, UErrorCode& status) {
- if (properties.currencyPluralInfo.fPtr.isNull()) {
- propertiesAPP.setTo(properties, status);
- currencyPluralInfoAPP.setToBogus();
- } else {
- propertiesAPP.setToBogus();
- currencyPluralInfoAPP.setTo(*properties.currencyPluralInfo.fPtr, properties, status);
- }
- }
-
- inline const AffixPatternProvider& get() const {
- if (!currencyPluralInfoAPP.isBogus()) {
- return currencyPluralInfoAPP;
- } else {
- return propertiesAPP;
- }
- }
-
- private:
- PropertiesAffixPatternProvider propertiesAPP;
- CurrencyPluralInfoAffixProvider currencyPluralInfoAPP;
-};
-
-
-/**
- * A struct for ownership of a few objects needed for formatting.
- */
-struct DecimalFormatWarehouse {
- AutoAffixPatternProvider affixProvider;
-
-};
-
-
-/**
-* Internal fields for DecimalFormat.
-* TODO: Make some of these fields by value instead of by LocalPointer?
-*/
-struct DecimalFormatFields : public UMemory {
-
- DecimalFormatFields() {}
-
- DecimalFormatFields(const DecimalFormatProperties& propsToCopy)
- : properties(propsToCopy) {}
-
- /** The property bag corresponding to user-specified settings and settings from the pattern string. */
- DecimalFormatProperties properties;
-
- /** The symbols for the current locale. */
- LocalPointer<const DecimalFormatSymbols> 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.
- */
- LocalizedNumberFormatter 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. */
- DecimalFormatProperties 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 */
+// © 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 <atomic>
+#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 AutoAffixPatternProvider;
+class CurrencyPluralInfoAffixProvider;
+
+
+class PropertiesAffixPatternProvider : public AffixPatternProvider, public UMemory {
+ public:
+ bool isBogus() const {
+ return fBogus;
+ }
+
+ void setToBogus() {
+ fBogus = true;
+ }
+
+ void setTo(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:
+ UnicodeString posPrefix;
+ UnicodeString posSuffix;
+ UnicodeString negPrefix;
+ UnicodeString negSuffix;
+ bool isCurrencyPattern;
+
+ PropertiesAffixPatternProvider() = default; // puts instance in valid but undefined state
+
+ const UnicodeString& getStringInternal(int32_t flags) const;
+
+ bool fBogus{true};
+
+ friend class AutoAffixPatternProvider;
+ friend class CurrencyPluralInfoAffixProvider;
+};
+
+
+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];
+
+ CurrencyPluralInfoAffixProvider() = default;
+
+ bool fBogus{true};
+
+ friend class AutoAffixPatternProvider;
+};
+
+
+class AutoAffixPatternProvider {
+ public:
+ inline AutoAffixPatternProvider() = default;
+
+ inline AutoAffixPatternProvider(const DecimalFormatProperties& properties, UErrorCode& status) {
+ setTo(properties, status);
+ }
+
+ inline void setTo(const DecimalFormatProperties& properties, UErrorCode& status) {
+ if (properties.currencyPluralInfo.fPtr.isNull()) {
+ propertiesAPP.setTo(properties, status);
+ currencyPluralInfoAPP.setToBogus();
+ } else {
+ propertiesAPP.setToBogus();
+ currencyPluralInfoAPP.setTo(*properties.currencyPluralInfo.fPtr, properties, status);
+ }
+ }
+
+ inline const AffixPatternProvider& get() const {
+ if (!currencyPluralInfoAPP.isBogus()) {
+ return currencyPluralInfoAPP;
+ } else {
+ return propertiesAPP;
+ }
+ }
+
+ private:
+ PropertiesAffixPatternProvider propertiesAPP;
+ CurrencyPluralInfoAffixProvider currencyPluralInfoAPP;
+};
+
+
+/**
+ * A struct for ownership of a few objects needed for formatting.
+ */
+struct DecimalFormatWarehouse {
+ AutoAffixPatternProvider affixProvider;
+
+};
+
+
+/**
+* Internal fields for DecimalFormat.
+* TODO: Make some of these fields by value instead of by LocalPointer?
+*/
+struct DecimalFormatFields : public UMemory {
+
+ DecimalFormatFields() {}
+
+ DecimalFormatFields(const DecimalFormatProperties& propsToCopy)
+ : properties(propsToCopy) {}
+
+ /** The property bag corresponding to user-specified settings and settings from the pattern string. */
+ DecimalFormatProperties properties;
+
+ /** The symbols for the current locale. */
+ LocalPointer<const DecimalFormatSymbols> 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.
+ */
+ LocalizedNumberFormatter 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. */
+ DecimalFormatProperties 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/contrib/libs/icu/i18n/number_microprops.h b/contrib/libs/icu/i18n/number_microprops.h
index 56512f5e6f..3f82a0c4b7 100644
--- a/contrib/libs/icu/i18n/number_microprops.h
+++ b/contrib/libs/icu/i18n/number_microprops.h
@@ -1,83 +1,83 @@
-// © 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;
- char nsName[9];
-
- // Note: This struct has no direct ownership of the following pointers.
- const DecimalFormatSymbols* symbols;
- const Modifier* modOuter;
- const Modifier* modMiddle = nullptr;
- 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 == &micros) {
- // 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 */
+// © 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;
+ char nsName[9];
+
+ // Note: This struct has no direct ownership of the following pointers.
+ const DecimalFormatSymbols* symbols;
+ const Modifier* modOuter;
+ const Modifier* modMiddle = nullptr;
+ 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 == &micros) {
+ // 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/contrib/libs/icu/i18n/number_modifiers.cpp b/contrib/libs/icu/i18n/number_modifiers.cpp
index 3becb7ba85..fb9ac8f650 100644
--- a/contrib/libs/icu/i18n/number_modifiers.cpp
+++ b/contrib/libs/icu/i18n/number_modifiers.cpp
@@ -1,485 +1,485 @@
-// © 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
-
-#include "umutex.h"
-#include "ucln_cmn.h"
-#include "ucln_in.h"
-#include "number_modifiers.h"
-
-using namespace icu;
-using namespace icu::number;
-using namespace icu::number::impl;
-
-namespace {
-
-// TODO: This is copied from simpleformatter.cpp
-const int32_t ARG_NUM_LIMIT = 0x100;
-
-// These are the default currency spacing UnicodeSets in CLDR.
-// Pre-compute them for performance.
-// The Java unit test testCurrencySpacingPatternStability() will start failing if these change in CLDR.
-icu::UInitOnce gDefaultCurrencySpacingInitOnce = U_INITONCE_INITIALIZER;
-
-UnicodeSet *UNISET_DIGIT = nullptr;
-UnicodeSet *UNISET_NOTS = nullptr;
-
-UBool U_CALLCONV cleanupDefaultCurrencySpacing() {
- delete UNISET_DIGIT;
- UNISET_DIGIT = nullptr;
- delete UNISET_NOTS;
- UNISET_NOTS = nullptr;
- gDefaultCurrencySpacingInitOnce.reset();
- return TRUE;
-}
-
-void U_CALLCONV initDefaultCurrencySpacing(UErrorCode &status) {
- ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY_SPACING, cleanupDefaultCurrencySpacing);
- UNISET_DIGIT = new UnicodeSet(UnicodeString(u"[:digit:]"), status);
- UNISET_NOTS = new UnicodeSet(UnicodeString(u"[:^S:]"), status);
- if (UNISET_DIGIT == nullptr || UNISET_NOTS == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- UNISET_DIGIT->freeze();
- UNISET_NOTS->freeze();
-}
-
-} // namespace
-
-
-Modifier::~Modifier() = default;
-
-Modifier::Parameters::Parameters()
- : obj(nullptr) {}
-
-Modifier::Parameters::Parameters(
- const ModifierStore* _obj, Signum _signum, StandardPlural::Form _plural)
- : obj(_obj), signum(_signum), plural(_plural) {}
-
-ModifierStore::~ModifierStore() = default;
-
-AdoptingModifierStore::~AdoptingModifierStore() {
- for (const Modifier *mod : mods) {
- delete mod;
- }
-}
-
-
-int32_t ConstantAffixModifier::apply(FormattedStringBuilder &output, int leftIndex, int rightIndex,
- UErrorCode &status) const {
- // Insert the suffix first since inserting the prefix will change the rightIndex
- int length = output.insert(rightIndex, fSuffix, fField, status);
- length += output.insert(leftIndex, fPrefix, fField, status);
- return length;
-}
-
-int32_t ConstantAffixModifier::getPrefixLength() const {
- return fPrefix.length();
-}
-
-int32_t ConstantAffixModifier::getCodePointCount() const {
- return fPrefix.countChar32() + fSuffix.countChar32();
-}
-
-bool ConstantAffixModifier::isStrong() const {
- return fStrong;
-}
-
-bool ConstantAffixModifier::containsField(Field field) const {
- (void)field;
- // This method is not currently used.
- UPRV_UNREACHABLE;
-}
-
-void ConstantAffixModifier::getParameters(Parameters& output) const {
- (void)output;
- // This method is not currently used.
- UPRV_UNREACHABLE;
-}
-
-bool ConstantAffixModifier::semanticallyEquivalent(const Modifier& other) const {
- auto* _other = dynamic_cast<const ConstantAffixModifier*>(&other);
- if (_other == nullptr) {
- return false;
- }
- return fPrefix == _other->fPrefix
- && fSuffix == _other->fSuffix
- && fField == _other->fField
- && fStrong == _other->fStrong;
-}
-
-
-SimpleModifier::SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong)
- : SimpleModifier(simpleFormatter, field, strong, {}) {}
-
-SimpleModifier::SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong,
- const Modifier::Parameters parameters)
- : fCompiledPattern(simpleFormatter.compiledPattern), fField(field), fStrong(strong),
- fParameters(parameters) {
- int32_t argLimit = SimpleFormatter::getArgumentLimit(
- fCompiledPattern.getBuffer(), fCompiledPattern.length());
- if (argLimit == 0) {
- // No arguments in compiled pattern
- fPrefixLength = fCompiledPattern.charAt(1) - ARG_NUM_LIMIT;
- U_ASSERT(2 + fPrefixLength == fCompiledPattern.length());
- // Set suffixOffset = -1 to indicate no arguments in compiled pattern.
- fSuffixOffset = -1;
- fSuffixLength = 0;
- } else {
- U_ASSERT(argLimit == 1);
- if (fCompiledPattern.charAt(1) != 0) {
- // Found prefix
- fPrefixLength = fCompiledPattern.charAt(1) - ARG_NUM_LIMIT;
- fSuffixOffset = 3 + fPrefixLength;
- } else {
- // No prefix
- fPrefixLength = 0;
- fSuffixOffset = 2;
- }
- if (3 + fPrefixLength < fCompiledPattern.length()) {
- // Found suffix
- fSuffixLength = fCompiledPattern.charAt(fSuffixOffset) - ARG_NUM_LIMIT;
- } else {
- // No suffix
- fSuffixLength = 0;
- }
- }
-}
-
-SimpleModifier::SimpleModifier()
- : fField(kUndefinedField), fStrong(false), fPrefixLength(0), fSuffixLength(0) {
-}
-
-int32_t SimpleModifier::apply(FormattedStringBuilder &output, int leftIndex, int rightIndex,
- UErrorCode &status) const {
- return formatAsPrefixSuffix(output, leftIndex, rightIndex, status);
-}
-
-int32_t SimpleModifier::getPrefixLength() const {
- return fPrefixLength;
-}
-
-int32_t SimpleModifier::getCodePointCount() const {
- int32_t count = 0;
- if (fPrefixLength > 0) {
- count += fCompiledPattern.countChar32(2, fPrefixLength);
- }
- if (fSuffixLength > 0) {
- count += fCompiledPattern.countChar32(1 + fSuffixOffset, fSuffixLength);
- }
- return count;
-}
-
-bool SimpleModifier::isStrong() const {
- return fStrong;
-}
-
-bool SimpleModifier::containsField(Field field) const {
- (void)field;
- // This method is not currently used.
- UPRV_UNREACHABLE;
-}
-
-void SimpleModifier::getParameters(Parameters& output) const {
- output = fParameters;
-}
-
-bool SimpleModifier::semanticallyEquivalent(const Modifier& other) const {
- auto* _other = dynamic_cast<const SimpleModifier*>(&other);
- if (_other == nullptr) {
- return false;
- }
- if (fParameters.obj != nullptr) {
- return fParameters.obj == _other->fParameters.obj;
- }
- return fCompiledPattern == _other->fCompiledPattern
- && fField == _other->fField
- && fStrong == _other->fStrong;
-}
-
-
-int32_t
-SimpleModifier::formatAsPrefixSuffix(FormattedStringBuilder &result, int32_t startIndex, int32_t endIndex,
- UErrorCode &status) const {
- if (fSuffixOffset == -1 && fPrefixLength + fSuffixLength > 0) {
- // There is no argument for the inner number; overwrite the entire segment with our string.
- return result.splice(startIndex, endIndex, fCompiledPattern, 2, 2 + fPrefixLength, fField, status);
- } else {
- if (fPrefixLength > 0) {
- result.insert(startIndex, fCompiledPattern, 2, 2 + fPrefixLength, fField, status);
- }
- if (fSuffixLength > 0) {
- result.insert(
- endIndex + fPrefixLength,
- fCompiledPattern,
- 1 + fSuffixOffset,
- 1 + fSuffixOffset + fSuffixLength,
- fField,
- status);
- }
- return fPrefixLength + fSuffixLength;
- }
-}
-
-
-int32_t
-SimpleModifier::formatTwoArgPattern(const SimpleFormatter& compiled, FormattedStringBuilder& result,
- int32_t index, int32_t* outPrefixLength, int32_t* outSuffixLength,
- Field field, UErrorCode& status) {
- const UnicodeString& compiledPattern = compiled.compiledPattern;
- int32_t argLimit = SimpleFormatter::getArgumentLimit(
- compiledPattern.getBuffer(), compiledPattern.length());
- if (argLimit != 2) {
- status = U_INTERNAL_PROGRAM_ERROR;
- return 0;
- }
- int32_t offset = 1; // offset into compiledPattern
- int32_t length = 0; // chars added to result
-
- int32_t prefixLength = compiledPattern.charAt(offset);
- offset++;
- if (prefixLength < ARG_NUM_LIMIT) {
- // No prefix
- prefixLength = 0;
- } else {
- prefixLength -= ARG_NUM_LIMIT;
- result.insert(index + length, compiledPattern, offset, offset + prefixLength, field, status);
- offset += prefixLength;
- length += prefixLength;
- offset++;
- }
-
- int32_t infixLength = compiledPattern.charAt(offset);
- offset++;
- if (infixLength < ARG_NUM_LIMIT) {
- // No infix
- infixLength = 0;
- } else {
- infixLength -= ARG_NUM_LIMIT;
- result.insert(index + length, compiledPattern, offset, offset + infixLength, field, status);
- offset += infixLength;
- length += infixLength;
- offset++;
- }
-
- int32_t suffixLength;
- if (offset == compiledPattern.length()) {
- // No suffix
- suffixLength = 0;
- } else {
- suffixLength = compiledPattern.charAt(offset) - ARG_NUM_LIMIT;
- offset++;
- result.insert(index + length, compiledPattern, offset, offset + suffixLength, field, status);
- length += suffixLength;
- }
-
- *outPrefixLength = prefixLength;
- *outSuffixLength = suffixLength;
-
- return length;
-}
-
-
-int32_t ConstantMultiFieldModifier::apply(FormattedStringBuilder &output, int leftIndex, int rightIndex,
- UErrorCode &status) const {
- int32_t length = output.insert(leftIndex, fPrefix, status);
- if (fOverwrite) {
- length += output.splice(
- leftIndex + length,
- rightIndex + length,
- UnicodeString(), 0, 0,
- kUndefinedField, status);
- }
- length += output.insert(rightIndex + length, fSuffix, status);
- return length;
-}
-
-int32_t ConstantMultiFieldModifier::getPrefixLength() const {
- return fPrefix.length();
-}
-
-int32_t ConstantMultiFieldModifier::getCodePointCount() const {
- return fPrefix.codePointCount() + fSuffix.codePointCount();
-}
-
-bool ConstantMultiFieldModifier::isStrong() const {
- return fStrong;
-}
-
-bool ConstantMultiFieldModifier::containsField(Field field) const {
- return fPrefix.containsField(field) || fSuffix.containsField(field);
-}
-
-void ConstantMultiFieldModifier::getParameters(Parameters& output) const {
- output = fParameters;
-}
-
-bool ConstantMultiFieldModifier::semanticallyEquivalent(const Modifier& other) const {
- auto* _other = dynamic_cast<const ConstantMultiFieldModifier*>(&other);
- if (_other == nullptr) {
- return false;
- }
- if (fParameters.obj != nullptr) {
- return fParameters.obj == _other->fParameters.obj;
- }
- return fPrefix.contentEquals(_other->fPrefix)
- && fSuffix.contentEquals(_other->fSuffix)
- && fOverwrite == _other->fOverwrite
- && fStrong == _other->fStrong;
-}
-
-
-CurrencySpacingEnabledModifier::CurrencySpacingEnabledModifier(const FormattedStringBuilder &prefix,
- const FormattedStringBuilder &suffix,
- bool overwrite,
- bool strong,
- const DecimalFormatSymbols &symbols,
- UErrorCode &status)
- : ConstantMultiFieldModifier(prefix, suffix, overwrite, strong) {
- // Check for currency spacing. Do not build the UnicodeSets unless there is
- // a currency code point at a boundary.
- if (prefix.length() > 0 && prefix.fieldAt(prefix.length() - 1) == Field(UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD)) {
- int prefixCp = prefix.getLastCodePoint();
- UnicodeSet prefixUnicodeSet = getUnicodeSet(symbols, IN_CURRENCY, PREFIX, status);
- if (prefixUnicodeSet.contains(prefixCp)) {
- fAfterPrefixUnicodeSet = getUnicodeSet(symbols, IN_NUMBER, PREFIX, status);
- fAfterPrefixUnicodeSet.freeze();
- fAfterPrefixInsert = getInsertString(symbols, PREFIX, status);
- } else {
- fAfterPrefixUnicodeSet.setToBogus();
- fAfterPrefixInsert.setToBogus();
- }
- } else {
- fAfterPrefixUnicodeSet.setToBogus();
- fAfterPrefixInsert.setToBogus();
- }
- if (suffix.length() > 0 && suffix.fieldAt(0) == Field(UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD)) {
- int suffixCp = suffix.getFirstCodePoint();
- UnicodeSet suffixUnicodeSet = getUnicodeSet(symbols, IN_CURRENCY, SUFFIX, status);
- if (suffixUnicodeSet.contains(suffixCp)) {
- fBeforeSuffixUnicodeSet = getUnicodeSet(symbols, IN_NUMBER, SUFFIX, status);
- fBeforeSuffixUnicodeSet.freeze();
- fBeforeSuffixInsert = getInsertString(symbols, SUFFIX, status);
- } else {
- fBeforeSuffixUnicodeSet.setToBogus();
- fBeforeSuffixInsert.setToBogus();
- }
- } else {
- fBeforeSuffixUnicodeSet.setToBogus();
- fBeforeSuffixInsert.setToBogus();
- }
-}
-
-int32_t CurrencySpacingEnabledModifier::apply(FormattedStringBuilder &output, int leftIndex, int rightIndex,
- UErrorCode &status) const {
- // Currency spacing logic
- int length = 0;
- if (rightIndex - leftIndex > 0 && !fAfterPrefixUnicodeSet.isBogus() &&
- fAfterPrefixUnicodeSet.contains(output.codePointAt(leftIndex))) {
- // TODO: Should we use the CURRENCY field here?
- length += output.insert(
- leftIndex,
- fAfterPrefixInsert,
- kUndefinedField,
- status);
- }
- if (rightIndex - leftIndex > 0 && !fBeforeSuffixUnicodeSet.isBogus() &&
- fBeforeSuffixUnicodeSet.contains(output.codePointBefore(rightIndex))) {
- // TODO: Should we use the CURRENCY field here?
- length += output.insert(
- rightIndex + length,
- fBeforeSuffixInsert,
- kUndefinedField,
- status);
- }
-
- // Call super for the remaining logic
- length += ConstantMultiFieldModifier::apply(output, leftIndex, rightIndex + length, status);
- return length;
-}
-
-int32_t
-CurrencySpacingEnabledModifier::applyCurrencySpacing(FormattedStringBuilder &output, int32_t prefixStart,
- int32_t prefixLen, int32_t suffixStart,
- int32_t suffixLen,
- const DecimalFormatSymbols &symbols,
- UErrorCode &status) {
- int length = 0;
- bool hasPrefix = (prefixLen > 0);
- bool hasSuffix = (suffixLen > 0);
- bool hasNumber = (suffixStart - prefixStart - prefixLen > 0); // could be empty string
- if (hasPrefix && hasNumber) {
- length += applyCurrencySpacingAffix(output, prefixStart + prefixLen, PREFIX, symbols, status);
- }
- if (hasSuffix && hasNumber) {
- length += applyCurrencySpacingAffix(output, suffixStart + length, SUFFIX, symbols, status);
- }
- return length;
-}
-
-int32_t
-CurrencySpacingEnabledModifier::applyCurrencySpacingAffix(FormattedStringBuilder &output, int32_t index,
- EAffix affix,
- const DecimalFormatSymbols &symbols,
- UErrorCode &status) {
- // NOTE: For prefix, output.fieldAt(index-1) gets the last field type in the prefix.
- // This works even if the last code point in the prefix is 2 code units because the
- // field value gets populated to both indices in the field array.
- Field affixField = (affix == PREFIX) ? output.fieldAt(index - 1) : output.fieldAt(index);
- if (affixField != Field(UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD)) {
- return 0;
- }
- int affixCp = (affix == PREFIX) ? output.codePointBefore(index) : output.codePointAt(index);
- UnicodeSet affixUniset = getUnicodeSet(symbols, IN_CURRENCY, affix, status);
- if (!affixUniset.contains(affixCp)) {
- return 0;
- }
- int numberCp = (affix == PREFIX) ? output.codePointAt(index) : output.codePointBefore(index);
- UnicodeSet numberUniset = getUnicodeSet(symbols, IN_NUMBER, affix, status);
- if (!numberUniset.contains(numberCp)) {
- return 0;
- }
- UnicodeString spacingString = getInsertString(symbols, affix, status);
-
- // NOTE: This next line *inserts* the spacing string, triggering an arraycopy.
- // It would be more efficient if this could be done before affixes were attached,
- // so that it could be prepended/appended instead of inserted.
- // However, the build code path is more efficient, and this is the most natural
- // place to put currency spacing in the non-build code path.
- // TODO: Should we use the CURRENCY field here?
- return output.insert(index, spacingString, kUndefinedField, status);
-}
-
-UnicodeSet
-CurrencySpacingEnabledModifier::getUnicodeSet(const DecimalFormatSymbols &symbols, EPosition position,
- EAffix affix, UErrorCode &status) {
- // Ensure the static defaults are initialized:
- umtx_initOnce(gDefaultCurrencySpacingInitOnce, &initDefaultCurrencySpacing, status);
- if (U_FAILURE(status)) {
- return UnicodeSet();
- }
-
- const UnicodeString& pattern = symbols.getPatternForCurrencySpacing(
- position == IN_CURRENCY ? UNUM_CURRENCY_MATCH : UNUM_CURRENCY_SURROUNDING_MATCH,
- affix == SUFFIX,
- status);
- if (pattern.compare(u"[:digit:]", -1) == 0) {
- return *UNISET_DIGIT;
- } else if (pattern.compare(u"[:^S:]", -1) == 0) {
- return *UNISET_NOTS;
- } else {
- return UnicodeSet(pattern, status);
- }
-}
-
-UnicodeString
-CurrencySpacingEnabledModifier::getInsertString(const DecimalFormatSymbols &symbols, EAffix affix,
- UErrorCode &status) {
- return symbols.getPatternForCurrencySpacing(UNUM_CURRENCY_INSERT, affix == SUFFIX, status);
-}
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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
+
+#include "umutex.h"
+#include "ucln_cmn.h"
+#include "ucln_in.h"
+#include "number_modifiers.h"
+
+using namespace icu;
+using namespace icu::number;
+using namespace icu::number::impl;
+
+namespace {
+
+// TODO: This is copied from simpleformatter.cpp
+const int32_t ARG_NUM_LIMIT = 0x100;
+
+// These are the default currency spacing UnicodeSets in CLDR.
+// Pre-compute them for performance.
+// The Java unit test testCurrencySpacingPatternStability() will start failing if these change in CLDR.
+icu::UInitOnce gDefaultCurrencySpacingInitOnce = U_INITONCE_INITIALIZER;
+
+UnicodeSet *UNISET_DIGIT = nullptr;
+UnicodeSet *UNISET_NOTS = nullptr;
+
+UBool U_CALLCONV cleanupDefaultCurrencySpacing() {
+ delete UNISET_DIGIT;
+ UNISET_DIGIT = nullptr;
+ delete UNISET_NOTS;
+ UNISET_NOTS = nullptr;
+ gDefaultCurrencySpacingInitOnce.reset();
+ return TRUE;
+}
+
+void U_CALLCONV initDefaultCurrencySpacing(UErrorCode &status) {
+ ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY_SPACING, cleanupDefaultCurrencySpacing);
+ UNISET_DIGIT = new UnicodeSet(UnicodeString(u"[:digit:]"), status);
+ UNISET_NOTS = new UnicodeSet(UnicodeString(u"[:^S:]"), status);
+ if (UNISET_DIGIT == nullptr || UNISET_NOTS == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ UNISET_DIGIT->freeze();
+ UNISET_NOTS->freeze();
+}
+
+} // namespace
+
+
+Modifier::~Modifier() = default;
+
+Modifier::Parameters::Parameters()
+ : obj(nullptr) {}
+
+Modifier::Parameters::Parameters(
+ const ModifierStore* _obj, Signum _signum, StandardPlural::Form _plural)
+ : obj(_obj), signum(_signum), plural(_plural) {}
+
+ModifierStore::~ModifierStore() = default;
+
+AdoptingModifierStore::~AdoptingModifierStore() {
+ for (const Modifier *mod : mods) {
+ delete mod;
+ }
+}
+
+
+int32_t ConstantAffixModifier::apply(FormattedStringBuilder &output, int leftIndex, int rightIndex,
+ UErrorCode &status) const {
+ // Insert the suffix first since inserting the prefix will change the rightIndex
+ int length = output.insert(rightIndex, fSuffix, fField, status);
+ length += output.insert(leftIndex, fPrefix, fField, status);
+ return length;
+}
+
+int32_t ConstantAffixModifier::getPrefixLength() const {
+ return fPrefix.length();
+}
+
+int32_t ConstantAffixModifier::getCodePointCount() const {
+ return fPrefix.countChar32() + fSuffix.countChar32();
+}
+
+bool ConstantAffixModifier::isStrong() const {
+ return fStrong;
+}
+
+bool ConstantAffixModifier::containsField(Field field) const {
+ (void)field;
+ // This method is not currently used.
+ UPRV_UNREACHABLE;
+}
+
+void ConstantAffixModifier::getParameters(Parameters& output) const {
+ (void)output;
+ // This method is not currently used.
+ UPRV_UNREACHABLE;
+}
+
+bool ConstantAffixModifier::semanticallyEquivalent(const Modifier& other) const {
+ auto* _other = dynamic_cast<const ConstantAffixModifier*>(&other);
+ if (_other == nullptr) {
+ return false;
+ }
+ return fPrefix == _other->fPrefix
+ && fSuffix == _other->fSuffix
+ && fField == _other->fField
+ && fStrong == _other->fStrong;
+}
+
+
+SimpleModifier::SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong)
+ : SimpleModifier(simpleFormatter, field, strong, {}) {}
+
+SimpleModifier::SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong,
+ const Modifier::Parameters parameters)
+ : fCompiledPattern(simpleFormatter.compiledPattern), fField(field), fStrong(strong),
+ fParameters(parameters) {
+ int32_t argLimit = SimpleFormatter::getArgumentLimit(
+ fCompiledPattern.getBuffer(), fCompiledPattern.length());
+ if (argLimit == 0) {
+ // No arguments in compiled pattern
+ fPrefixLength = fCompiledPattern.charAt(1) - ARG_NUM_LIMIT;
+ U_ASSERT(2 + fPrefixLength == fCompiledPattern.length());
+ // Set suffixOffset = -1 to indicate no arguments in compiled pattern.
+ fSuffixOffset = -1;
+ fSuffixLength = 0;
+ } else {
+ U_ASSERT(argLimit == 1);
+ if (fCompiledPattern.charAt(1) != 0) {
+ // Found prefix
+ fPrefixLength = fCompiledPattern.charAt(1) - ARG_NUM_LIMIT;
+ fSuffixOffset = 3 + fPrefixLength;
+ } else {
+ // No prefix
+ fPrefixLength = 0;
+ fSuffixOffset = 2;
+ }
+ if (3 + fPrefixLength < fCompiledPattern.length()) {
+ // Found suffix
+ fSuffixLength = fCompiledPattern.charAt(fSuffixOffset) - ARG_NUM_LIMIT;
+ } else {
+ // No suffix
+ fSuffixLength = 0;
+ }
+ }
+}
+
+SimpleModifier::SimpleModifier()
+ : fField(kUndefinedField), fStrong(false), fPrefixLength(0), fSuffixLength(0) {
+}
+
+int32_t SimpleModifier::apply(FormattedStringBuilder &output, int leftIndex, int rightIndex,
+ UErrorCode &status) const {
+ return formatAsPrefixSuffix(output, leftIndex, rightIndex, status);
+}
+
+int32_t SimpleModifier::getPrefixLength() const {
+ return fPrefixLength;
+}
+
+int32_t SimpleModifier::getCodePointCount() const {
+ int32_t count = 0;
+ if (fPrefixLength > 0) {
+ count += fCompiledPattern.countChar32(2, fPrefixLength);
+ }
+ if (fSuffixLength > 0) {
+ count += fCompiledPattern.countChar32(1 + fSuffixOffset, fSuffixLength);
+ }
+ return count;
+}
+
+bool SimpleModifier::isStrong() const {
+ return fStrong;
+}
+
+bool SimpleModifier::containsField(Field field) const {
+ (void)field;
+ // This method is not currently used.
+ UPRV_UNREACHABLE;
+}
+
+void SimpleModifier::getParameters(Parameters& output) const {
+ output = fParameters;
+}
+
+bool SimpleModifier::semanticallyEquivalent(const Modifier& other) const {
+ auto* _other = dynamic_cast<const SimpleModifier*>(&other);
+ if (_other == nullptr) {
+ return false;
+ }
+ if (fParameters.obj != nullptr) {
+ return fParameters.obj == _other->fParameters.obj;
+ }
+ return fCompiledPattern == _other->fCompiledPattern
+ && fField == _other->fField
+ && fStrong == _other->fStrong;
+}
+
+
+int32_t
+SimpleModifier::formatAsPrefixSuffix(FormattedStringBuilder &result, int32_t startIndex, int32_t endIndex,
+ UErrorCode &status) const {
+ if (fSuffixOffset == -1 && fPrefixLength + fSuffixLength > 0) {
+ // There is no argument for the inner number; overwrite the entire segment with our string.
+ return result.splice(startIndex, endIndex, fCompiledPattern, 2, 2 + fPrefixLength, fField, status);
+ } else {
+ if (fPrefixLength > 0) {
+ result.insert(startIndex, fCompiledPattern, 2, 2 + fPrefixLength, fField, status);
+ }
+ if (fSuffixLength > 0) {
+ result.insert(
+ endIndex + fPrefixLength,
+ fCompiledPattern,
+ 1 + fSuffixOffset,
+ 1 + fSuffixOffset + fSuffixLength,
+ fField,
+ status);
+ }
+ return fPrefixLength + fSuffixLength;
+ }
+}
+
+
+int32_t
+SimpleModifier::formatTwoArgPattern(const SimpleFormatter& compiled, FormattedStringBuilder& result,
+ int32_t index, int32_t* outPrefixLength, int32_t* outSuffixLength,
+ Field field, UErrorCode& status) {
+ const UnicodeString& compiledPattern = compiled.compiledPattern;
+ int32_t argLimit = SimpleFormatter::getArgumentLimit(
+ compiledPattern.getBuffer(), compiledPattern.length());
+ if (argLimit != 2) {
+ status = U_INTERNAL_PROGRAM_ERROR;
+ return 0;
+ }
+ int32_t offset = 1; // offset into compiledPattern
+ int32_t length = 0; // chars added to result
+
+ int32_t prefixLength = compiledPattern.charAt(offset);
+ offset++;
+ if (prefixLength < ARG_NUM_LIMIT) {
+ // No prefix
+ prefixLength = 0;
+ } else {
+ prefixLength -= ARG_NUM_LIMIT;
+ result.insert(index + length, compiledPattern, offset, offset + prefixLength, field, status);
+ offset += prefixLength;
+ length += prefixLength;
+ offset++;
+ }
+
+ int32_t infixLength = compiledPattern.charAt(offset);
+ offset++;
+ if (infixLength < ARG_NUM_LIMIT) {
+ // No infix
+ infixLength = 0;
+ } else {
+ infixLength -= ARG_NUM_LIMIT;
+ result.insert(index + length, compiledPattern, offset, offset + infixLength, field, status);
+ offset += infixLength;
+ length += infixLength;
+ offset++;
+ }
+
+ int32_t suffixLength;
+ if (offset == compiledPattern.length()) {
+ // No suffix
+ suffixLength = 0;
+ } else {
+ suffixLength = compiledPattern.charAt(offset) - ARG_NUM_LIMIT;
+ offset++;
+ result.insert(index + length, compiledPattern, offset, offset + suffixLength, field, status);
+ length += suffixLength;
+ }
+
+ *outPrefixLength = prefixLength;
+ *outSuffixLength = suffixLength;
+
+ return length;
+}
+
+
+int32_t ConstantMultiFieldModifier::apply(FormattedStringBuilder &output, int leftIndex, int rightIndex,
+ UErrorCode &status) const {
+ int32_t length = output.insert(leftIndex, fPrefix, status);
+ if (fOverwrite) {
+ length += output.splice(
+ leftIndex + length,
+ rightIndex + length,
+ UnicodeString(), 0, 0,
+ kUndefinedField, status);
+ }
+ length += output.insert(rightIndex + length, fSuffix, status);
+ return length;
+}
+
+int32_t ConstantMultiFieldModifier::getPrefixLength() const {
+ return fPrefix.length();
+}
+
+int32_t ConstantMultiFieldModifier::getCodePointCount() const {
+ return fPrefix.codePointCount() + fSuffix.codePointCount();
+}
+
+bool ConstantMultiFieldModifier::isStrong() const {
+ return fStrong;
+}
+
+bool ConstantMultiFieldModifier::containsField(Field field) const {
+ return fPrefix.containsField(field) || fSuffix.containsField(field);
+}
+
+void ConstantMultiFieldModifier::getParameters(Parameters& output) const {
+ output = fParameters;
+}
+
+bool ConstantMultiFieldModifier::semanticallyEquivalent(const Modifier& other) const {
+ auto* _other = dynamic_cast<const ConstantMultiFieldModifier*>(&other);
+ if (_other == nullptr) {
+ return false;
+ }
+ if (fParameters.obj != nullptr) {
+ return fParameters.obj == _other->fParameters.obj;
+ }
+ return fPrefix.contentEquals(_other->fPrefix)
+ && fSuffix.contentEquals(_other->fSuffix)
+ && fOverwrite == _other->fOverwrite
+ && fStrong == _other->fStrong;
+}
+
+
+CurrencySpacingEnabledModifier::CurrencySpacingEnabledModifier(const FormattedStringBuilder &prefix,
+ const FormattedStringBuilder &suffix,
+ bool overwrite,
+ bool strong,
+ const DecimalFormatSymbols &symbols,
+ UErrorCode &status)
+ : ConstantMultiFieldModifier(prefix, suffix, overwrite, strong) {
+ // Check for currency spacing. Do not build the UnicodeSets unless there is
+ // a currency code point at a boundary.
+ if (prefix.length() > 0 && prefix.fieldAt(prefix.length() - 1) == Field(UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD)) {
+ int prefixCp = prefix.getLastCodePoint();
+ UnicodeSet prefixUnicodeSet = getUnicodeSet(symbols, IN_CURRENCY, PREFIX, status);
+ if (prefixUnicodeSet.contains(prefixCp)) {
+ fAfterPrefixUnicodeSet = getUnicodeSet(symbols, IN_NUMBER, PREFIX, status);
+ fAfterPrefixUnicodeSet.freeze();
+ fAfterPrefixInsert = getInsertString(symbols, PREFIX, status);
+ } else {
+ fAfterPrefixUnicodeSet.setToBogus();
+ fAfterPrefixInsert.setToBogus();
+ }
+ } else {
+ fAfterPrefixUnicodeSet.setToBogus();
+ fAfterPrefixInsert.setToBogus();
+ }
+ if (suffix.length() > 0 && suffix.fieldAt(0) == Field(UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD)) {
+ int suffixCp = suffix.getFirstCodePoint();
+ UnicodeSet suffixUnicodeSet = getUnicodeSet(symbols, IN_CURRENCY, SUFFIX, status);
+ if (suffixUnicodeSet.contains(suffixCp)) {
+ fBeforeSuffixUnicodeSet = getUnicodeSet(symbols, IN_NUMBER, SUFFIX, status);
+ fBeforeSuffixUnicodeSet.freeze();
+ fBeforeSuffixInsert = getInsertString(symbols, SUFFIX, status);
+ } else {
+ fBeforeSuffixUnicodeSet.setToBogus();
+ fBeforeSuffixInsert.setToBogus();
+ }
+ } else {
+ fBeforeSuffixUnicodeSet.setToBogus();
+ fBeforeSuffixInsert.setToBogus();
+ }
+}
+
+int32_t CurrencySpacingEnabledModifier::apply(FormattedStringBuilder &output, int leftIndex, int rightIndex,
+ UErrorCode &status) const {
+ // Currency spacing logic
+ int length = 0;
+ if (rightIndex - leftIndex > 0 && !fAfterPrefixUnicodeSet.isBogus() &&
+ fAfterPrefixUnicodeSet.contains(output.codePointAt(leftIndex))) {
+ // TODO: Should we use the CURRENCY field here?
+ length += output.insert(
+ leftIndex,
+ fAfterPrefixInsert,
+ kUndefinedField,
+ status);
+ }
+ if (rightIndex - leftIndex > 0 && !fBeforeSuffixUnicodeSet.isBogus() &&
+ fBeforeSuffixUnicodeSet.contains(output.codePointBefore(rightIndex))) {
+ // TODO: Should we use the CURRENCY field here?
+ length += output.insert(
+ rightIndex + length,
+ fBeforeSuffixInsert,
+ kUndefinedField,
+ status);
+ }
+
+ // Call super for the remaining logic
+ length += ConstantMultiFieldModifier::apply(output, leftIndex, rightIndex + length, status);
+ return length;
+}
+
+int32_t
+CurrencySpacingEnabledModifier::applyCurrencySpacing(FormattedStringBuilder &output, int32_t prefixStart,
+ int32_t prefixLen, int32_t suffixStart,
+ int32_t suffixLen,
+ const DecimalFormatSymbols &symbols,
+ UErrorCode &status) {
+ int length = 0;
+ bool hasPrefix = (prefixLen > 0);
+ bool hasSuffix = (suffixLen > 0);
+ bool hasNumber = (suffixStart - prefixStart - prefixLen > 0); // could be empty string
+ if (hasPrefix && hasNumber) {
+ length += applyCurrencySpacingAffix(output, prefixStart + prefixLen, PREFIX, symbols, status);
+ }
+ if (hasSuffix && hasNumber) {
+ length += applyCurrencySpacingAffix(output, suffixStart + length, SUFFIX, symbols, status);
+ }
+ return length;
+}
+
+int32_t
+CurrencySpacingEnabledModifier::applyCurrencySpacingAffix(FormattedStringBuilder &output, int32_t index,
+ EAffix affix,
+ const DecimalFormatSymbols &symbols,
+ UErrorCode &status) {
+ // NOTE: For prefix, output.fieldAt(index-1) gets the last field type in the prefix.
+ // This works even if the last code point in the prefix is 2 code units because the
+ // field value gets populated to both indices in the field array.
+ Field affixField = (affix == PREFIX) ? output.fieldAt(index - 1) : output.fieldAt(index);
+ if (affixField != Field(UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD)) {
+ return 0;
+ }
+ int affixCp = (affix == PREFIX) ? output.codePointBefore(index) : output.codePointAt(index);
+ UnicodeSet affixUniset = getUnicodeSet(symbols, IN_CURRENCY, affix, status);
+ if (!affixUniset.contains(affixCp)) {
+ return 0;
+ }
+ int numberCp = (affix == PREFIX) ? output.codePointAt(index) : output.codePointBefore(index);
+ UnicodeSet numberUniset = getUnicodeSet(symbols, IN_NUMBER, affix, status);
+ if (!numberUniset.contains(numberCp)) {
+ return 0;
+ }
+ UnicodeString spacingString = getInsertString(symbols, affix, status);
+
+ // NOTE: This next line *inserts* the spacing string, triggering an arraycopy.
+ // It would be more efficient if this could be done before affixes were attached,
+ // so that it could be prepended/appended instead of inserted.
+ // However, the build code path is more efficient, and this is the most natural
+ // place to put currency spacing in the non-build code path.
+ // TODO: Should we use the CURRENCY field here?
+ return output.insert(index, spacingString, kUndefinedField, status);
+}
+
+UnicodeSet
+CurrencySpacingEnabledModifier::getUnicodeSet(const DecimalFormatSymbols &symbols, EPosition position,
+ EAffix affix, UErrorCode &status) {
+ // Ensure the static defaults are initialized:
+ umtx_initOnce(gDefaultCurrencySpacingInitOnce, &initDefaultCurrencySpacing, status);
+ if (U_FAILURE(status)) {
+ return UnicodeSet();
+ }
+
+ const UnicodeString& pattern = symbols.getPatternForCurrencySpacing(
+ position == IN_CURRENCY ? UNUM_CURRENCY_MATCH : UNUM_CURRENCY_SURROUNDING_MATCH,
+ affix == SUFFIX,
+ status);
+ if (pattern.compare(u"[:digit:]", -1) == 0) {
+ return *UNISET_DIGIT;
+ } else if (pattern.compare(u"[:^S:]", -1) == 0) {
+ return *UNISET_NOTS;
+ } else {
+ return UnicodeSet(pattern, status);
+ }
+}
+
+UnicodeString
+CurrencySpacingEnabledModifier::getInsertString(const DecimalFormatSymbols &symbols, EAffix affix,
+ UErrorCode &status) {
+ return symbols.getPatternForCurrencySpacing(UNUM_CURRENCY_INSERT, affix == SUFFIX, status);
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_modifiers.h b/contrib/libs/icu/i18n/number_modifiers.h
index 375254310c..760fde12f3 100644
--- a/contrib/libs/icu/i18n/number_modifiers.h
+++ b/contrib/libs/icu/i18n/number_modifiers.h
@@ -1,338 +1,338 @@
-// © 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_MODIFIERS_H__
-#define __NUMBER_MODIFIERS_H__
-
-#include <algorithm>
-#include <cstdint>
-#include "unicode/uniset.h"
-#include "unicode/simpleformatter.h"
-#include "standardplural.h"
-#include "formatted_string_builder.h"
-#include "number_types.h"
-
-U_NAMESPACE_BEGIN namespace number {
-namespace impl {
-
-/**
- * The canonical implementation of {@link Modifier}, containing a prefix and suffix string.
- * TODO: This is not currently being used by real code and could be removed.
- */
-class U_I18N_API ConstantAffixModifier : public Modifier, public UObject {
- public:
- ConstantAffixModifier(const UnicodeString &prefix, const UnicodeString &suffix, Field field,
- bool strong)
- : fPrefix(prefix), fSuffix(suffix), fField(field), fStrong(strong) {}
-
- int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
- UErrorCode &status) const U_OVERRIDE;
-
- int32_t getPrefixLength() const U_OVERRIDE;
-
- int32_t getCodePointCount() const U_OVERRIDE;
-
- bool isStrong() const U_OVERRIDE;
-
- bool containsField(Field field) const U_OVERRIDE;
-
- void getParameters(Parameters& output) const U_OVERRIDE;
-
- bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
-
- private:
- UnicodeString fPrefix;
- UnicodeString fSuffix;
- Field fField;
- bool fStrong;
-};
-
-/**
- * The second primary implementation of {@link Modifier}, this one consuming a {@link SimpleFormatter}
- * pattern.
- */
-class U_I18N_API SimpleModifier : public Modifier, public UMemory {
- public:
- SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong);
-
- SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong,
- const Modifier::Parameters parameters);
-
- // Default constructor for LongNameHandler.h
- SimpleModifier();
-
- int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
- UErrorCode &status) const U_OVERRIDE;
-
- int32_t getPrefixLength() const U_OVERRIDE;
-
- int32_t getCodePointCount() const U_OVERRIDE;
-
- bool isStrong() const U_OVERRIDE;
-
- bool containsField(Field field) const U_OVERRIDE;
-
- void getParameters(Parameters& output) const U_OVERRIDE;
-
- bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
-
- /**
- * TODO: This belongs in SimpleFormatterImpl. The only reason I haven't moved it there yet is because
- * FormattedStringBuilder is an internal class and SimpleFormatterImpl feels like it should not depend on it.
- *
- * <p>
- * Formats a value that is already stored inside the StringBuilder <code>result</code> between the indices
- * <code>startIndex</code> and <code>endIndex</code> by inserting characters before the start index and after the
- * end index.
- *
- * <p>
- * This is well-defined only for patterns with exactly one argument.
- *
- * @param result
- * The StringBuilder containing the value argument.
- * @param startIndex
- * The left index of the value within the string builder.
- * @param endIndex
- * The right index of the value within the string builder.
- * @return The number of characters (UTF-16 code points) that were added to the StringBuilder.
- */
- int32_t
- formatAsPrefixSuffix(FormattedStringBuilder& result, int32_t startIndex, int32_t endIndex,
- UErrorCode& status) const;
-
- /**
- * TODO: Like above, this belongs with the rest of the SimpleFormatterImpl code.
- * I put it here so that the SimpleFormatter uses in FormattedStringBuilder are near each other.
- *
- * <p>
- * Applies the compiled two-argument pattern to the FormattedStringBuilder.
- *
- * <p>
- * This method is optimized for the case where the prefix and suffix are often empty, such as
- * in the range pattern like "{0}-{1}".
- */
- static int32_t
- formatTwoArgPattern(const SimpleFormatter& compiled, FormattedStringBuilder& result,
- int32_t index, int32_t* outPrefixLength, int32_t* outSuffixLength,
- Field field, UErrorCode& status);
-
- private:
- UnicodeString fCompiledPattern;
- Field fField;
- bool fStrong = false;
- int32_t fPrefixLength = 0;
- int32_t fSuffixOffset = -1;
- int32_t fSuffixLength = 0;
- Modifier::Parameters fParameters;
-};
-
-/**
- * An implementation of {@link Modifier} that allows for multiple types of fields in the same modifier. Constructed
- * based on the contents of two {@link FormattedStringBuilder} instances (one for the prefix, one for the suffix).
- */
-class U_I18N_API ConstantMultiFieldModifier : public Modifier, public UMemory {
- public:
- ConstantMultiFieldModifier(
- const FormattedStringBuilder &prefix,
- const FormattedStringBuilder &suffix,
- bool overwrite,
- bool strong,
- const Modifier::Parameters parameters)
- : fPrefix(prefix),
- fSuffix(suffix),
- fOverwrite(overwrite),
- fStrong(strong),
- fParameters(parameters) {}
-
- ConstantMultiFieldModifier(
- const FormattedStringBuilder &prefix,
- const FormattedStringBuilder &suffix,
- bool overwrite,
- bool strong)
- : fPrefix(prefix),
- fSuffix(suffix),
- fOverwrite(overwrite),
- fStrong(strong) {}
-
- int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
- UErrorCode &status) const U_OVERRIDE;
-
- int32_t getPrefixLength() const U_OVERRIDE;
-
- int32_t getCodePointCount() const U_OVERRIDE;
-
- bool isStrong() const U_OVERRIDE;
-
- bool containsField(Field field) const U_OVERRIDE;
-
- void getParameters(Parameters& output) const U_OVERRIDE;
-
- bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
-
- protected:
- // NOTE: In Java, these are stored as array pointers. In C++, the FormattedStringBuilder is stored by
- // value and is treated internally as immutable.
- FormattedStringBuilder fPrefix;
- FormattedStringBuilder fSuffix;
- bool fOverwrite;
- bool fStrong;
- Modifier::Parameters fParameters;
-};
-
-/** Identical to {@link ConstantMultiFieldModifier}, but supports currency spacing. */
-class U_I18N_API CurrencySpacingEnabledModifier : public ConstantMultiFieldModifier {
- public:
- /** Safe code path */
- CurrencySpacingEnabledModifier(
- const FormattedStringBuilder &prefix,
- const FormattedStringBuilder &suffix,
- bool overwrite,
- bool strong,
- const DecimalFormatSymbols &symbols,
- UErrorCode &status);
-
- int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
- UErrorCode &status) const U_OVERRIDE;
-
- /** Unsafe code path */
- static int32_t
- applyCurrencySpacing(FormattedStringBuilder &output, int32_t prefixStart, int32_t prefixLen,
- int32_t suffixStart, int32_t suffixLen, const DecimalFormatSymbols &symbols,
- UErrorCode &status);
-
- private:
- UnicodeSet fAfterPrefixUnicodeSet;
- UnicodeString fAfterPrefixInsert;
- UnicodeSet fBeforeSuffixUnicodeSet;
- UnicodeString fBeforeSuffixInsert;
-
- enum EAffix {
- PREFIX, SUFFIX
- };
-
- enum EPosition {
- IN_CURRENCY, IN_NUMBER
- };
-
- /** Unsafe code path */
- static int32_t applyCurrencySpacingAffix(FormattedStringBuilder &output, int32_t index, EAffix affix,
- const DecimalFormatSymbols &symbols, UErrorCode &status);
-
- static UnicodeSet
- getUnicodeSet(const DecimalFormatSymbols &symbols, EPosition position, EAffix affix,
- UErrorCode &status);
-
- static UnicodeString
- getInsertString(const DecimalFormatSymbols &symbols, EAffix affix, UErrorCode &status);
-};
-
-/** A Modifier that does not do anything. */
-class U_I18N_API EmptyModifier : public Modifier, public UMemory {
- public:
- explicit EmptyModifier(bool isStrong) : fStrong(isStrong) {}
-
- int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
- UErrorCode &status) const U_OVERRIDE {
- (void)output;
- (void)leftIndex;
- (void)rightIndex;
- (void)status;
- return 0;
- }
-
- int32_t getPrefixLength() const U_OVERRIDE {
- return 0;
- }
-
- int32_t getCodePointCount() const U_OVERRIDE {
- return 0;
- }
-
- bool isStrong() const U_OVERRIDE {
- return fStrong;
- }
-
- bool containsField(Field field) const U_OVERRIDE {
- (void)field;
- return false;
- }
-
- void getParameters(Parameters& output) const U_OVERRIDE {
- output.obj = nullptr;
- }
-
- bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE {
- return other.getCodePointCount() == 0;
- }
-
- private:
- bool fStrong;
-};
-
-/**
- * This implementation of ModifierStore adopts Modifer pointers.
- */
-class U_I18N_API AdoptingModifierStore : public ModifierStore, public UMemory {
- public:
- virtual ~AdoptingModifierStore();
-
- static constexpr StandardPlural::Form DEFAULT_STANDARD_PLURAL = StandardPlural::OTHER;
-
- AdoptingModifierStore() = default;
-
- // No copying!
- AdoptingModifierStore(const AdoptingModifierStore &other) = delete;
-
- /**
- * Sets the Modifier with the specified signum and plural form.
- */
- void adoptModifier(Signum signum, StandardPlural::Form plural, const Modifier *mod) {
- U_ASSERT(mods[getModIndex(signum, plural)] == nullptr);
- mods[getModIndex(signum, plural)] = mod;
- }
-
- /**
- * Sets the Modifier with the specified signum.
- * The modifier will apply to all plural forms.
- */
- void adoptModifierWithoutPlural(Signum signum, const Modifier *mod) {
- U_ASSERT(mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)] == nullptr);
- mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)] = mod;
- }
-
- /** Returns a reference to the modifier; no ownership change. */
- const Modifier *getModifier(Signum signum, StandardPlural::Form plural) const U_OVERRIDE {
- const Modifier* modifier = mods[getModIndex(signum, plural)];
- if (modifier == nullptr && plural != DEFAULT_STANDARD_PLURAL) {
- modifier = mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)];
- }
- return modifier;
- }
-
- /** Returns a reference to the modifier; no ownership change. */
- const Modifier *getModifierWithoutPlural(Signum signum) const {
- return mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)];
- }
-
- private:
- // NOTE: mods is zero-initialized (to nullptr)
- const Modifier *mods[4 * StandardPlural::COUNT] = {};
-
- inline static int32_t getModIndex(Signum signum, StandardPlural::Form plural) {
- U_ASSERT(signum >= 0 && signum < SIGNUM_COUNT);
- U_ASSERT(plural >= 0 && plural < StandardPlural::COUNT);
- return static_cast<int32_t>(plural) * SIGNUM_COUNT + signum;
- }
-};
-
-} // namespace impl
-} // namespace number
-U_NAMESPACE_END
-
-
-#endif //__NUMBER_MODIFIERS_H__
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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_MODIFIERS_H__
+#define __NUMBER_MODIFIERS_H__
+
+#include <algorithm>
+#include <cstdint>
+#include "unicode/uniset.h"
+#include "unicode/simpleformatter.h"
+#include "standardplural.h"
+#include "formatted_string_builder.h"
+#include "number_types.h"
+
+U_NAMESPACE_BEGIN namespace number {
+namespace impl {
+
+/**
+ * The canonical implementation of {@link Modifier}, containing a prefix and suffix string.
+ * TODO: This is not currently being used by real code and could be removed.
+ */
+class U_I18N_API ConstantAffixModifier : public Modifier, public UObject {
+ public:
+ ConstantAffixModifier(const UnicodeString &prefix, const UnicodeString &suffix, Field field,
+ bool strong)
+ : fPrefix(prefix), fSuffix(suffix), fField(field), fStrong(strong) {}
+
+ int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
+ UErrorCode &status) const U_OVERRIDE;
+
+ int32_t getPrefixLength() const U_OVERRIDE;
+
+ int32_t getCodePointCount() const U_OVERRIDE;
+
+ bool isStrong() const U_OVERRIDE;
+
+ bool containsField(Field field) const U_OVERRIDE;
+
+ void getParameters(Parameters& output) const U_OVERRIDE;
+
+ bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
+
+ private:
+ UnicodeString fPrefix;
+ UnicodeString fSuffix;
+ Field fField;
+ bool fStrong;
+};
+
+/**
+ * The second primary implementation of {@link Modifier}, this one consuming a {@link SimpleFormatter}
+ * pattern.
+ */
+class U_I18N_API SimpleModifier : public Modifier, public UMemory {
+ public:
+ SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong);
+
+ SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong,
+ const Modifier::Parameters parameters);
+
+ // Default constructor for LongNameHandler.h
+ SimpleModifier();
+
+ int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
+ UErrorCode &status) const U_OVERRIDE;
+
+ int32_t getPrefixLength() const U_OVERRIDE;
+
+ int32_t getCodePointCount() const U_OVERRIDE;
+
+ bool isStrong() const U_OVERRIDE;
+
+ bool containsField(Field field) const U_OVERRIDE;
+
+ void getParameters(Parameters& output) const U_OVERRIDE;
+
+ bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
+
+ /**
+ * TODO: This belongs in SimpleFormatterImpl. The only reason I haven't moved it there yet is because
+ * FormattedStringBuilder is an internal class and SimpleFormatterImpl feels like it should not depend on it.
+ *
+ * <p>
+ * Formats a value that is already stored inside the StringBuilder <code>result</code> between the indices
+ * <code>startIndex</code> and <code>endIndex</code> by inserting characters before the start index and after the
+ * end index.
+ *
+ * <p>
+ * This is well-defined only for patterns with exactly one argument.
+ *
+ * @param result
+ * The StringBuilder containing the value argument.
+ * @param startIndex
+ * The left index of the value within the string builder.
+ * @param endIndex
+ * The right index of the value within the string builder.
+ * @return The number of characters (UTF-16 code points) that were added to the StringBuilder.
+ */
+ int32_t
+ formatAsPrefixSuffix(FormattedStringBuilder& result, int32_t startIndex, int32_t endIndex,
+ UErrorCode& status) const;
+
+ /**
+ * TODO: Like above, this belongs with the rest of the SimpleFormatterImpl code.
+ * I put it here so that the SimpleFormatter uses in FormattedStringBuilder are near each other.
+ *
+ * <p>
+ * Applies the compiled two-argument pattern to the FormattedStringBuilder.
+ *
+ * <p>
+ * This method is optimized for the case where the prefix and suffix are often empty, such as
+ * in the range pattern like "{0}-{1}".
+ */
+ static int32_t
+ formatTwoArgPattern(const SimpleFormatter& compiled, FormattedStringBuilder& result,
+ int32_t index, int32_t* outPrefixLength, int32_t* outSuffixLength,
+ Field field, UErrorCode& status);
+
+ private:
+ UnicodeString fCompiledPattern;
+ Field fField;
+ bool fStrong = false;
+ int32_t fPrefixLength = 0;
+ int32_t fSuffixOffset = -1;
+ int32_t fSuffixLength = 0;
+ Modifier::Parameters fParameters;
+};
+
+/**
+ * An implementation of {@link Modifier} that allows for multiple types of fields in the same modifier. Constructed
+ * based on the contents of two {@link FormattedStringBuilder} instances (one for the prefix, one for the suffix).
+ */
+class U_I18N_API ConstantMultiFieldModifier : public Modifier, public UMemory {
+ public:
+ ConstantMultiFieldModifier(
+ const FormattedStringBuilder &prefix,
+ const FormattedStringBuilder &suffix,
+ bool overwrite,
+ bool strong,
+ const Modifier::Parameters parameters)
+ : fPrefix(prefix),
+ fSuffix(suffix),
+ fOverwrite(overwrite),
+ fStrong(strong),
+ fParameters(parameters) {}
+
+ ConstantMultiFieldModifier(
+ const FormattedStringBuilder &prefix,
+ const FormattedStringBuilder &suffix,
+ bool overwrite,
+ bool strong)
+ : fPrefix(prefix),
+ fSuffix(suffix),
+ fOverwrite(overwrite),
+ fStrong(strong) {}
+
+ int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
+ UErrorCode &status) const U_OVERRIDE;
+
+ int32_t getPrefixLength() const U_OVERRIDE;
+
+ int32_t getCodePointCount() const U_OVERRIDE;
+
+ bool isStrong() const U_OVERRIDE;
+
+ bool containsField(Field field) const U_OVERRIDE;
+
+ void getParameters(Parameters& output) const U_OVERRIDE;
+
+ bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
+
+ protected:
+ // NOTE: In Java, these are stored as array pointers. In C++, the FormattedStringBuilder is stored by
+ // value and is treated internally as immutable.
+ FormattedStringBuilder fPrefix;
+ FormattedStringBuilder fSuffix;
+ bool fOverwrite;
+ bool fStrong;
+ Modifier::Parameters fParameters;
+};
+
+/** Identical to {@link ConstantMultiFieldModifier}, but supports currency spacing. */
+class U_I18N_API CurrencySpacingEnabledModifier : public ConstantMultiFieldModifier {
+ public:
+ /** Safe code path */
+ CurrencySpacingEnabledModifier(
+ const FormattedStringBuilder &prefix,
+ const FormattedStringBuilder &suffix,
+ bool overwrite,
+ bool strong,
+ const DecimalFormatSymbols &symbols,
+ UErrorCode &status);
+
+ int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
+ UErrorCode &status) const U_OVERRIDE;
+
+ /** Unsafe code path */
+ static int32_t
+ applyCurrencySpacing(FormattedStringBuilder &output, int32_t prefixStart, int32_t prefixLen,
+ int32_t suffixStart, int32_t suffixLen, const DecimalFormatSymbols &symbols,
+ UErrorCode &status);
+
+ private:
+ UnicodeSet fAfterPrefixUnicodeSet;
+ UnicodeString fAfterPrefixInsert;
+ UnicodeSet fBeforeSuffixUnicodeSet;
+ UnicodeString fBeforeSuffixInsert;
+
+ enum EAffix {
+ PREFIX, SUFFIX
+ };
+
+ enum EPosition {
+ IN_CURRENCY, IN_NUMBER
+ };
+
+ /** Unsafe code path */
+ static int32_t applyCurrencySpacingAffix(FormattedStringBuilder &output, int32_t index, EAffix affix,
+ const DecimalFormatSymbols &symbols, UErrorCode &status);
+
+ static UnicodeSet
+ getUnicodeSet(const DecimalFormatSymbols &symbols, EPosition position, EAffix affix,
+ UErrorCode &status);
+
+ static UnicodeString
+ getInsertString(const DecimalFormatSymbols &symbols, EAffix affix, UErrorCode &status);
+};
+
+/** A Modifier that does not do anything. */
+class U_I18N_API EmptyModifier : public Modifier, public UMemory {
+ public:
+ explicit EmptyModifier(bool isStrong) : fStrong(isStrong) {}
+
+ int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
+ UErrorCode &status) const U_OVERRIDE {
+ (void)output;
+ (void)leftIndex;
+ (void)rightIndex;
+ (void)status;
+ return 0;
+ }
+
+ int32_t getPrefixLength() const U_OVERRIDE {
+ return 0;
+ }
+
+ int32_t getCodePointCount() const U_OVERRIDE {
+ return 0;
+ }
+
+ bool isStrong() const U_OVERRIDE {
+ return fStrong;
+ }
+
+ bool containsField(Field field) const U_OVERRIDE {
+ (void)field;
+ return false;
+ }
+
+ void getParameters(Parameters& output) const U_OVERRIDE {
+ output.obj = nullptr;
+ }
+
+ bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE {
+ return other.getCodePointCount() == 0;
+ }
+
+ private:
+ bool fStrong;
+};
+
+/**
+ * This implementation of ModifierStore adopts Modifer pointers.
+ */
+class U_I18N_API AdoptingModifierStore : public ModifierStore, public UMemory {
+ public:
+ virtual ~AdoptingModifierStore();
+
+ static constexpr StandardPlural::Form DEFAULT_STANDARD_PLURAL = StandardPlural::OTHER;
+
+ AdoptingModifierStore() = default;
+
+ // No copying!
+ AdoptingModifierStore(const AdoptingModifierStore &other) = delete;
+
+ /**
+ * Sets the Modifier with the specified signum and plural form.
+ */
+ void adoptModifier(Signum signum, StandardPlural::Form plural, const Modifier *mod) {
+ U_ASSERT(mods[getModIndex(signum, plural)] == nullptr);
+ mods[getModIndex(signum, plural)] = mod;
+ }
+
+ /**
+ * Sets the Modifier with the specified signum.
+ * The modifier will apply to all plural forms.
+ */
+ void adoptModifierWithoutPlural(Signum signum, const Modifier *mod) {
+ U_ASSERT(mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)] == nullptr);
+ mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)] = mod;
+ }
+
+ /** Returns a reference to the modifier; no ownership change. */
+ const Modifier *getModifier(Signum signum, StandardPlural::Form plural) const U_OVERRIDE {
+ const Modifier* modifier = mods[getModIndex(signum, plural)];
+ if (modifier == nullptr && plural != DEFAULT_STANDARD_PLURAL) {
+ modifier = mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)];
+ }
+ return modifier;
+ }
+
+ /** Returns a reference to the modifier; no ownership change. */
+ const Modifier *getModifierWithoutPlural(Signum signum) const {
+ return mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)];
+ }
+
+ private:
+ // NOTE: mods is zero-initialized (to nullptr)
+ const Modifier *mods[4 * StandardPlural::COUNT] = {};
+
+ inline static int32_t getModIndex(Signum signum, StandardPlural::Form plural) {
+ U_ASSERT(signum >= 0 && signum < SIGNUM_COUNT);
+ U_ASSERT(plural >= 0 && plural < StandardPlural::COUNT);
+ return static_cast<int32_t>(plural) * SIGNUM_COUNT + signum;
+ }
+};
+
+} // namespace impl
+} // namespace number
+U_NAMESPACE_END
+
+
+#endif //__NUMBER_MODIFIERS_H__
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_multiplier.cpp b/contrib/libs/icu/i18n/number_multiplier.cpp
index 8f07e548de..f97a757403 100644
--- a/contrib/libs/icu/i18n/number_multiplier.cpp
+++ b/contrib/libs/icu/i18n/number_multiplier.cpp
@@ -1,159 +1,159 @@
-// © 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;
- if (fArbitrary != nullptr) {
- delete fArbitrary;
- }
- 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> 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> 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> 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) {
- fMultiplier = multiplier;
- fParent = parent;
-}
-
-void MultiplierFormatHandler::processQuantity(DecimalQuantity& quantity, MicroProps& micros,
- UErrorCode& status) const {
- fParent->processQuantity(quantity, micros, status);
- fMultiplier.applyTo(quantity);
-}
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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;
+ if (fArbitrary != nullptr) {
+ delete fArbitrary;
+ }
+ 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> 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> 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> 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) {
+ fMultiplier = multiplier;
+ fParent = parent;
+}
+
+void MultiplierFormatHandler::processQuantity(DecimalQuantity& quantity, MicroProps& micros,
+ UErrorCode& status) const {
+ fParent->processQuantity(quantity, micros, status);
+ fMultiplier.applyTo(quantity);
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_multiplier.h b/contrib/libs/icu/i18n/number_multiplier.h
index d8235dc601..6f4cb837ac 100644
--- a/contrib/libs/icu/i18n/number_multiplier.h
+++ b/contrib/libs/icu/i18n/number_multiplier.h
@@ -1,57 +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 fMultiplier;
- const MicroPropsGenerator *fParent;
-};
-
-
-/** 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 */
+// © 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 fMultiplier;
+ const MicroPropsGenerator *fParent;
+};
+
+
+/** 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/contrib/libs/icu/i18n/number_notation.cpp b/contrib/libs/icu/i18n/number_notation.cpp
index b3cabb57a5..bf6b8179d9 100644
--- a/contrib/libs/icu/i18n/number_notation.cpp
+++ b/contrib/libs/icu/i18n/number_notation.cpp
@@ -1,88 +1,88 @@
-// © 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
-
-#include "unicode/numberformatter.h"
-#include "number_types.h"
-
-using namespace icu;
-using namespace icu::number;
-using namespace icu::number::impl;
-
-
-ScientificNotation Notation::scientific() {
- // NOTE: ISO C++ does not allow C99 designated initializers.
- ScientificSettings settings;
- settings.fEngineeringInterval = 1;
- settings.fRequireMinInt = false;
- settings.fMinExponentDigits = 1;
- settings.fExponentSignDisplay = UNUM_SIGN_AUTO;
- NotationUnion union_;
- union_.scientific = settings;
- return {NTN_SCIENTIFIC, union_};
-}
-
-ScientificNotation Notation::engineering() {
- ScientificSettings settings;
- settings.fEngineeringInterval = 3;
- settings.fRequireMinInt = false;
- settings.fMinExponentDigits = 1;
- settings.fExponentSignDisplay = UNUM_SIGN_AUTO;
- NotationUnion union_;
- union_.scientific = settings;
- 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;
- return {NTN_COMPACT, union_};
-}
-
-Notation Notation::compactLong() {
- NotationUnion union_;
- union_.compactStyle = CompactStyle::UNUM_LONG;
- return {NTN_COMPACT, union_};
-}
-
-Notation Notation::simple() {
- return {};
-}
-
-ScientificNotation
-ScientificNotation::withMinExponentDigits(int32_t minExponentDigits) const {
- if (minExponentDigits >= 1 && minExponentDigits <= kMaxIntFracSig) {
- ScientificSettings settings = fUnion.scientific;
- settings.fMinExponentDigits = static_cast<digits_t>(minExponentDigits);
- NotationUnion union_ = {settings};
- return {NTN_SCIENTIFIC, union_};
- } else {
- return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
- }
-}
-
-ScientificNotation
-ScientificNotation::withExponentSignDisplay(UNumberSignDisplay exponentSignDisplay) const {
- ScientificSettings settings = fUnion.scientific;
- settings.fExponentSignDisplay = exponentSignDisplay;
- NotationUnion union_ = {settings};
- return {NTN_SCIENTIFIC, union_};
-}
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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
+
+#include "unicode/numberformatter.h"
+#include "number_types.h"
+
+using namespace icu;
+using namespace icu::number;
+using namespace icu::number::impl;
+
+
+ScientificNotation Notation::scientific() {
+ // NOTE: ISO C++ does not allow C99 designated initializers.
+ ScientificSettings settings;
+ settings.fEngineeringInterval = 1;
+ settings.fRequireMinInt = false;
+ settings.fMinExponentDigits = 1;
+ settings.fExponentSignDisplay = UNUM_SIGN_AUTO;
+ NotationUnion union_;
+ union_.scientific = settings;
+ return {NTN_SCIENTIFIC, union_};
+}
+
+ScientificNotation Notation::engineering() {
+ ScientificSettings settings;
+ settings.fEngineeringInterval = 3;
+ settings.fRequireMinInt = false;
+ settings.fMinExponentDigits = 1;
+ settings.fExponentSignDisplay = UNUM_SIGN_AUTO;
+ NotationUnion union_;
+ union_.scientific = settings;
+ 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;
+ return {NTN_COMPACT, union_};
+}
+
+Notation Notation::compactLong() {
+ NotationUnion union_;
+ union_.compactStyle = CompactStyle::UNUM_LONG;
+ return {NTN_COMPACT, union_};
+}
+
+Notation Notation::simple() {
+ return {};
+}
+
+ScientificNotation
+ScientificNotation::withMinExponentDigits(int32_t minExponentDigits) const {
+ if (minExponentDigits >= 1 && minExponentDigits <= kMaxIntFracSig) {
+ ScientificSettings settings = fUnion.scientific;
+ settings.fMinExponentDigits = static_cast<digits_t>(minExponentDigits);
+ NotationUnion union_ = {settings};
+ return {NTN_SCIENTIFIC, union_};
+ } else {
+ return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
+ }
+}
+
+ScientificNotation
+ScientificNotation::withExponentSignDisplay(UNumberSignDisplay exponentSignDisplay) const {
+ ScientificSettings settings = fUnion.scientific;
+ settings.fExponentSignDisplay = exponentSignDisplay;
+ NotationUnion union_ = {settings};
+ return {NTN_SCIENTIFIC, union_};
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_output.cpp b/contrib/libs/icu/i18n/number_output.cpp
index 40192a9225..face1bb166 100644
--- a/contrib/libs/icu/i18n/number_output.cpp
+++ b/contrib/libs/icu/i18n/number_output.cpp
@@ -1,47 +1,47 @@
-// © 2019 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html
-
-#include "unicode/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/numberformatter.h"
-#include "number_utypes.h"
-#include "util.h"
-#include "number_decimalquantity.h"
-#include "number_decnum.h"
-
-U_NAMESPACE_BEGIN
-namespace number {
-
-
-UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(FormattedNumber)
-
-#define UPRV_NOARG
-
-void FormattedNumber::toDecimalNumber(ByteSink& sink, UErrorCode& status) const {
- UPRV_FORMATTED_VALUE_METHOD_GUARD(UPRV_NOARG)
- impl::DecNum decnum;
- fData->quantity.toDecNum(decnum, status);
- decnum.toString(sink, status);
-}
-
-void FormattedNumber::getAllFieldPositionsImpl(FieldPositionIteratorHandler& fpih,
- UErrorCode& status) const {
- UPRV_FORMATTED_VALUE_METHOD_GUARD(UPRV_NOARG)
- fData->getAllFieldPositions(fpih, status);
-}
-
-void FormattedNumber::getDecimalQuantity(impl::DecimalQuantity& output, UErrorCode& status) const {
- UPRV_FORMATTED_VALUE_METHOD_GUARD(UPRV_NOARG)
- output = fData->quantity;
-}
-
-
-impl::UFormattedNumberData::~UFormattedNumberData() = default;
-
-
-} // namespace number
-U_NAMESPACE_END
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 2019 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/numberformatter.h"
+#include "number_utypes.h"
+#include "util.h"
+#include "number_decimalquantity.h"
+#include "number_decnum.h"
+
+U_NAMESPACE_BEGIN
+namespace number {
+
+
+UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(FormattedNumber)
+
+#define UPRV_NOARG
+
+void FormattedNumber::toDecimalNumber(ByteSink& sink, UErrorCode& status) const {
+ UPRV_FORMATTED_VALUE_METHOD_GUARD(UPRV_NOARG)
+ impl::DecNum decnum;
+ fData->quantity.toDecNum(decnum, status);
+ decnum.toString(sink, status);
+}
+
+void FormattedNumber::getAllFieldPositionsImpl(FieldPositionIteratorHandler& fpih,
+ UErrorCode& status) const {
+ UPRV_FORMATTED_VALUE_METHOD_GUARD(UPRV_NOARG)
+ fData->getAllFieldPositions(fpih, status);
+}
+
+void FormattedNumber::getDecimalQuantity(impl::DecimalQuantity& output, UErrorCode& status) const {
+ UPRV_FORMATTED_VALUE_METHOD_GUARD(UPRV_NOARG)
+ output = fData->quantity;
+}
+
+
+impl::UFormattedNumberData::~UFormattedNumberData() = default;
+
+
+} // namespace number
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_padding.cpp b/contrib/libs/icu/i18n/number_padding.cpp
index c320c3ffb6..52fff0497b 100644
--- a/contrib/libs/icu/i18n/number_padding.cpp
+++ b/contrib/libs/icu/i18n/number_padding.cpp
@@ -1,96 +1,96 @@
-// © 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
-
-#include "unicode/numberformatter.h"
-#include "number_types.h"
-#include "formatted_string_builder.h"
-#include "number_decimfmtprops.h"
-
-using namespace icu;
-using namespace icu::number;
-using namespace icu::number::impl;
-
-namespace {
-
-int32_t
-addPaddingHelper(UChar32 paddingCp, int32_t requiredPadding, FormattedStringBuilder &string, int32_t index,
- UErrorCode &status) {
- for (int32_t i = 0; i < requiredPadding; i++) {
- // TODO: If appending to the end, this will cause actual insertion operations. Improve.
- string.insertCodePoint(index, paddingCp, kUndefinedField, status);
- }
- return U16_LENGTH(paddingCp) * requiredPadding;
-}
-
-}
-
-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;
-}
-
-Padder::Padder(int32_t width) : fWidth(width) {}
-
-Padder Padder::none() {
- return {-1};
-}
-
-Padder Padder::codePoints(UChar32 cp, int32_t targetWidth, UNumberFormatPadPosition position) {
- // TODO: Validate the code point?
- if (targetWidth >= 0) {
- return {cp, targetWidth, position};
- } else {
- return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
- }
-}
-
-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,
- FormattedStringBuilder &string, int32_t leftIndex, int32_t rightIndex,
- UErrorCode &status) const {
- int32_t modLength = mod1.getCodePointCount() + mod2.getCodePointCount();
- int32_t requiredPadding = fWidth - modLength - string.codePointCount();
- U_ASSERT(leftIndex == 0 &&
- rightIndex == string.length()); // fix the previous line to remove this assertion
-
- int length = 0;
- if (requiredPadding <= 0) {
- // Padding is not required.
- length += mod1.apply(string, leftIndex, rightIndex, status);
- length += mod2.apply(string, leftIndex, rightIndex + length, status);
- return length;
- }
-
- PadPosition position = fUnion.padding.fPosition;
- UChar32 paddingCp = fUnion.padding.fCp;
- if (position == UNUM_PAD_AFTER_PREFIX) {
- length += addPaddingHelper(paddingCp, requiredPadding, string, leftIndex, status);
- } else if (position == UNUM_PAD_BEFORE_SUFFIX) {
- length += addPaddingHelper(paddingCp, requiredPadding, string, rightIndex + length, status);
- }
- length += mod1.apply(string, leftIndex, rightIndex + length, status);
- length += mod2.apply(string, leftIndex, rightIndex + length, status);
- if (position == UNUM_PAD_BEFORE_PREFIX) {
- length += addPaddingHelper(paddingCp, requiredPadding, string, leftIndex, status);
- } else if (position == UNUM_PAD_AFTER_SUFFIX) {
- length += addPaddingHelper(paddingCp, requiredPadding, string, rightIndex + length, status);
- }
-
- return length;
-}
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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
+
+#include "unicode/numberformatter.h"
+#include "number_types.h"
+#include "formatted_string_builder.h"
+#include "number_decimfmtprops.h"
+
+using namespace icu;
+using namespace icu::number;
+using namespace icu::number::impl;
+
+namespace {
+
+int32_t
+addPaddingHelper(UChar32 paddingCp, int32_t requiredPadding, FormattedStringBuilder &string, int32_t index,
+ UErrorCode &status) {
+ for (int32_t i = 0; i < requiredPadding; i++) {
+ // TODO: If appending to the end, this will cause actual insertion operations. Improve.
+ string.insertCodePoint(index, paddingCp, kUndefinedField, status);
+ }
+ return U16_LENGTH(paddingCp) * requiredPadding;
+}
+
+}
+
+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;
+}
+
+Padder::Padder(int32_t width) : fWidth(width) {}
+
+Padder Padder::none() {
+ return {-1};
+}
+
+Padder Padder::codePoints(UChar32 cp, int32_t targetWidth, UNumberFormatPadPosition position) {
+ // TODO: Validate the code point?
+ if (targetWidth >= 0) {
+ return {cp, targetWidth, position};
+ } else {
+ return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
+ }
+}
+
+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,
+ FormattedStringBuilder &string, int32_t leftIndex, int32_t rightIndex,
+ UErrorCode &status) const {
+ int32_t modLength = mod1.getCodePointCount() + mod2.getCodePointCount();
+ int32_t requiredPadding = fWidth - modLength - string.codePointCount();
+ U_ASSERT(leftIndex == 0 &&
+ rightIndex == string.length()); // fix the previous line to remove this assertion
+
+ int length = 0;
+ if (requiredPadding <= 0) {
+ // Padding is not required.
+ length += mod1.apply(string, leftIndex, rightIndex, status);
+ length += mod2.apply(string, leftIndex, rightIndex + length, status);
+ return length;
+ }
+
+ PadPosition position = fUnion.padding.fPosition;
+ UChar32 paddingCp = fUnion.padding.fCp;
+ if (position == UNUM_PAD_AFTER_PREFIX) {
+ length += addPaddingHelper(paddingCp, requiredPadding, string, leftIndex, status);
+ } else if (position == UNUM_PAD_BEFORE_SUFFIX) {
+ length += addPaddingHelper(paddingCp, requiredPadding, string, rightIndex + length, status);
+ }
+ length += mod1.apply(string, leftIndex, rightIndex + length, status);
+ length += mod2.apply(string, leftIndex, rightIndex + length, status);
+ if (position == UNUM_PAD_BEFORE_PREFIX) {
+ length += addPaddingHelper(paddingCp, requiredPadding, string, leftIndex, status);
+ } else if (position == UNUM_PAD_AFTER_SUFFIX) {
+ length += addPaddingHelper(paddingCp, requiredPadding, string, rightIndex + length, status);
+ }
+
+ return length;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_patternmodifier.cpp b/contrib/libs/icu/i18n/number_patternmodifier.cpp
index 45602942ae..8a0cd74f7f 100644
--- a/contrib/libs/icu/i18n/number_patternmodifier.cpp
+++ b/contrib/libs/icu/i18n/number_patternmodifier.cpp
@@ -1,330 +1,330 @@
-// © 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
-
-#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;
-
-
-AffixPatternProvider::~AffixPatternProvider() = default;
-
-
-MutablePatternModifier::MutablePatternModifier(bool isStrong)
- : fStrong(isStrong) {}
-
-void MutablePatternModifier::setPatternInfo(const AffixPatternProvider* patternInfo, Field field) {
- fPatternInfo = patternInfo;
- fField = field;
-}
-
-void MutablePatternModifier::setPatternAttributes(UNumberSignDisplay signDisplay, bool perMille) {
- fSignDisplay = signDisplay;
- fPerMilleReplacesPercent = perMille;
-}
-
-void MutablePatternModifier::setSymbols(const DecimalFormatSymbols* symbols,
- const CurrencyUnit& currency,
- const UNumberUnitWidth unitWidth,
- const PluralRules* rules,
- UErrorCode& status) {
- U_ASSERT((rules != nullptr) == needsPlurals());
- fSymbols = symbols;
- fCurrencySymbols = {currency, symbols->getLocale(), *symbols, status};
- fUnitWidth = unitWidth;
- fRules = rules;
-}
-
-void MutablePatternModifier::setNumberProperties(Signum signum, StandardPlural::Form plural) {
- fSignum = signum;
- fPlural = plural;
-}
-
-bool MutablePatternModifier::needsPlurals() const {
- UErrorCode statusLocal = U_ZERO_ERROR;
- return fPatternInfo->containsSymbolType(AffixPatternType::TYPE_CURRENCY_TRIPLE, statusLocal);
- // Silently ignore any error codes.
-}
-
-ImmutablePatternModifier* MutablePatternModifier::createImmutable(UErrorCode& status) {
- // TODO: Move StandardPlural VALUES to standardplural.h
- static const StandardPlural::Form STANDARD_PLURAL_VALUES[] = {
- StandardPlural::Form::ZERO,
- StandardPlural::Form::ONE,
- StandardPlural::Form::TWO,
- StandardPlural::Form::FEW,
- StandardPlural::Form::MANY,
- StandardPlural::Form::OTHER};
-
- auto pm = new AdoptingModifierStore();
- if (pm == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
-
- if (needsPlurals()) {
- // Slower path when we require the plural keyword.
- for (StandardPlural::Form plural : STANDARD_PLURAL_VALUES) {
- setNumberProperties(SIGNUM_POS, plural);
- pm->adoptModifier(SIGNUM_POS, plural, createConstantModifier(status));
- setNumberProperties(SIGNUM_NEG_ZERO, plural);
- pm->adoptModifier(SIGNUM_NEG_ZERO, plural, createConstantModifier(status));
- setNumberProperties(SIGNUM_POS_ZERO, plural);
- pm->adoptModifier(SIGNUM_POS_ZERO, plural, createConstantModifier(status));
- setNumberProperties(SIGNUM_NEG, plural);
- pm->adoptModifier(SIGNUM_NEG, plural, createConstantModifier(status));
- }
- if (U_FAILURE(status)) {
- delete pm;
- return nullptr;
- }
- return new ImmutablePatternModifier(pm, fRules); // adopts pm
- } else {
- // Faster path when plural keyword is not needed.
- setNumberProperties(SIGNUM_POS, StandardPlural::Form::COUNT);
- pm->adoptModifierWithoutPlural(SIGNUM_POS, createConstantModifier(status));
- setNumberProperties(SIGNUM_NEG_ZERO, StandardPlural::Form::COUNT);
- pm->adoptModifierWithoutPlural(SIGNUM_NEG_ZERO, createConstantModifier(status));
- setNumberProperties(SIGNUM_POS_ZERO, StandardPlural::Form::COUNT);
- pm->adoptModifierWithoutPlural(SIGNUM_POS_ZERO, createConstantModifier(status));
- setNumberProperties(SIGNUM_NEG, StandardPlural::Form::COUNT);
- pm->adoptModifierWithoutPlural(SIGNUM_NEG, createConstantModifier(status));
- if (U_FAILURE(status)) {
- delete pm;
- return nullptr;
- }
- return new ImmutablePatternModifier(pm, nullptr); // adopts pm
- }
-}
-
-ConstantMultiFieldModifier* MutablePatternModifier::createConstantModifier(UErrorCode& status) {
- FormattedStringBuilder a;
- FormattedStringBuilder b;
- insertPrefix(a, 0, status);
- insertSuffix(b, 0, status);
- if (fPatternInfo->hasCurrencySign()) {
- return new CurrencySpacingEnabledModifier(
- a, b, !fPatternInfo->hasBody(), fStrong, *fSymbols, status);
- } else {
- return new ConstantMultiFieldModifier(a, b, !fPatternInfo->hasBody(), fStrong);
- }
-}
-
-ImmutablePatternModifier::ImmutablePatternModifier(AdoptingModifierStore* pm, const PluralRules* rules)
- : pm(pm), rules(rules), parent(nullptr) {}
-
-void ImmutablePatternModifier::processQuantity(DecimalQuantity& quantity, MicroProps& micros,
- UErrorCode& status) const {
- parent->processQuantity(quantity, micros, status);
- micros.rounder.apply(quantity, status);
- if (micros.modMiddle != nullptr) {
- return;
- }
- applyToMicros(micros, quantity, status);
-}
-
-void ImmutablePatternModifier::applyToMicros(
- MicroProps& micros, const DecimalQuantity& quantity, UErrorCode& status) const {
- if (rules == nullptr) {
- micros.modMiddle = pm->getModifierWithoutPlural(quantity.signum());
- } else {
- StandardPlural::Form pluralForm = utils::getPluralSafe(micros.rounder, rules, quantity, status);
- micros.modMiddle = pm->getModifier(quantity.signum(), pluralForm);
- }
-}
-
-const Modifier* ImmutablePatternModifier::getModifier(Signum signum, StandardPlural::Form plural) const {
- if (rules == nullptr) {
- return pm->getModifierWithoutPlural(signum);
- } else {
- return pm->getModifier(signum, plural);
- }
-}
-
-void ImmutablePatternModifier::addToChain(const MicroPropsGenerator* parent) {
- this->parent = parent;
-}
-
-
-/** Used by the unsafe code path. */
-MicroPropsGenerator& MutablePatternModifier::addToChain(const MicroPropsGenerator* parent) {
- fParent = parent;
- return *this;
-}
-
-void MutablePatternModifier::processQuantity(DecimalQuantity& fq, MicroProps& micros,
- UErrorCode& status) const {
- fParent->processQuantity(fq, micros, status);
- micros.rounder.apply(fq, status);
- if (micros.modMiddle != nullptr) {
- return;
- }
- // 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<MutablePatternModifier*>(this);
- if (needsPlurals()) {
- StandardPlural::Form pluralForm = utils::getPluralSafe(micros.rounder, fRules, fq, status);
- nonConstThis->setNumberProperties(fq.signum(), pluralForm);
- } else {
- nonConstThis->setNumberProperties(fq.signum(), StandardPlural::Form::COUNT);
- }
- micros.modMiddle = this;
-}
-
-int32_t MutablePatternModifier::apply(FormattedStringBuilder& 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<MutablePatternModifier*>(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 (!fPatternInfo->hasBody()) {
- overwriteLen = output.splice(
- leftIndex + prefixLen,
- rightIndex + prefixLen,
- UnicodeString(),
- 0,
- 0,
- kUndefinedField,
- status);
- }
- CurrencySpacingEnabledModifier::applyCurrencySpacing(
- output,
- leftIndex,
- prefixLen,
- rightIndex + overwriteLen + prefixLen,
- suffixLen,
- *fSymbols,
- status);
- return prefixLen + overwriteLen + suffixLen;
-}
-
-int32_t MutablePatternModifier::getPrefixLength() 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<MutablePatternModifier*>(this);
-
- // Enter and exit CharSequence Mode to get the length.
- UErrorCode status = U_ZERO_ERROR; // status fails only with an iilegal argument exception
- nonConstThis->prepareAffix(true);
- int result = AffixUtils::unescapedCodePointCount(currentAffix, *this, status); // prefix length
- return result;
-}
-
-int32_t MutablePatternModifier::getCodePointCount() 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<MutablePatternModifier*>(this);
-
- // Render the affixes to get the length
- UErrorCode status = U_ZERO_ERROR; // status fails only with an iilegal argument exception
- 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;
-}
-
-bool MutablePatternModifier::isStrong() const {
- return fStrong;
-}
-
-bool MutablePatternModifier::containsField(Field field) const {
- (void)field;
- // This method is not currently used.
- UPRV_UNREACHABLE;
-}
-
-void MutablePatternModifier::getParameters(Parameters& output) const {
- (void)output;
- // This method is not currently used.
- UPRV_UNREACHABLE;
-}
-
-bool MutablePatternModifier::semanticallyEquivalent(const Modifier& other) const {
- (void)other;
- // This method is not currently used.
- UPRV_UNREACHABLE;
-}
-
-int32_t MutablePatternModifier::insertPrefix(FormattedStringBuilder& sb, int position, UErrorCode& status) {
- prepareAffix(true);
- int32_t length = AffixUtils::unescape(currentAffix, sb, position, *this, fField, status);
- return length;
-}
-
-int32_t MutablePatternModifier::insertSuffix(FormattedStringBuilder& sb, int position, UErrorCode& status) {
- prepareAffix(false);
- int32_t length = AffixUtils::unescape(currentAffix, sb, position, *this, fField, status);
- return length;
-}
-
-/** This method contains the heart of the logic for rendering LDML affix strings. */
-void MutablePatternModifier::prepareAffix(bool isPrefix) {
- PatternStringUtils::patternInfoToStringBuilder(
- *fPatternInfo,
- isPrefix,
- PatternStringUtils::resolveSignDisplay(fSignDisplay, fSignum),
- fPlural,
- fPerMilleReplacesPercent,
- currentAffix);
-}
-
-UnicodeString MutablePatternModifier::getSymbol(AffixPatternType type) const {
- UErrorCode localStatus = U_ZERO_ERROR;
- switch (type) {
- case AffixPatternType::TYPE_MINUS_SIGN:
- return fSymbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kMinusSignSymbol);
- case AffixPatternType::TYPE_PLUS_SIGN:
- return fSymbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPlusSignSymbol);
- case AffixPatternType::TYPE_PERCENT:
- return fSymbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPercentSymbol);
- case AffixPatternType::TYPE_PERMILLE:
- return fSymbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPerMillSymbol);
- case AffixPatternType::TYPE_CURRENCY_SINGLE: {
- // UnitWidth ISO and HIDDEN overrides the singular currency symbol.
- if (fUnitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE) {
- return fCurrencySymbols.getIntlCurrencySymbol(localStatus);
- } else if (fUnitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_HIDDEN) {
- return UnicodeString();
- } else if (fUnitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW) {
- return fCurrencySymbols.getNarrowCurrencySymbol(localStatus);
- } else {
- return fCurrencySymbols.getCurrencySymbol(localStatus);
- }
- }
- case AffixPatternType::TYPE_CURRENCY_DOUBLE:
- return fCurrencySymbols.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(fPlural != StandardPlural::Form::COUNT);
- return fCurrencySymbols.getPluralName(fPlural, localStatus);
- case AffixPatternType::TYPE_CURRENCY_QUAD:
- return UnicodeString(u"\uFFFD");
- case AffixPatternType::TYPE_CURRENCY_QUINT:
- return UnicodeString(u"\uFFFD");
- default:
- UPRV_UNREACHABLE;
- }
-}
-
-UnicodeString MutablePatternModifier::toUnicodeString() const {
- // Never called by AffixUtils
- UPRV_UNREACHABLE;
-}
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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
+
+#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;
+
+
+AffixPatternProvider::~AffixPatternProvider() = default;
+
+
+MutablePatternModifier::MutablePatternModifier(bool isStrong)
+ : fStrong(isStrong) {}
+
+void MutablePatternModifier::setPatternInfo(const AffixPatternProvider* patternInfo, Field field) {
+ fPatternInfo = patternInfo;
+ fField = field;
+}
+
+void MutablePatternModifier::setPatternAttributes(UNumberSignDisplay signDisplay, bool perMille) {
+ fSignDisplay = signDisplay;
+ fPerMilleReplacesPercent = perMille;
+}
+
+void MutablePatternModifier::setSymbols(const DecimalFormatSymbols* symbols,
+ const CurrencyUnit& currency,
+ const UNumberUnitWidth unitWidth,
+ const PluralRules* rules,
+ UErrorCode& status) {
+ U_ASSERT((rules != nullptr) == needsPlurals());
+ fSymbols = symbols;
+ fCurrencySymbols = {currency, symbols->getLocale(), *symbols, status};
+ fUnitWidth = unitWidth;
+ fRules = rules;
+}
+
+void MutablePatternModifier::setNumberProperties(Signum signum, StandardPlural::Form plural) {
+ fSignum = signum;
+ fPlural = plural;
+}
+
+bool MutablePatternModifier::needsPlurals() const {
+ UErrorCode statusLocal = U_ZERO_ERROR;
+ return fPatternInfo->containsSymbolType(AffixPatternType::TYPE_CURRENCY_TRIPLE, statusLocal);
+ // Silently ignore any error codes.
+}
+
+ImmutablePatternModifier* MutablePatternModifier::createImmutable(UErrorCode& status) {
+ // TODO: Move StandardPlural VALUES to standardplural.h
+ static const StandardPlural::Form STANDARD_PLURAL_VALUES[] = {
+ StandardPlural::Form::ZERO,
+ StandardPlural::Form::ONE,
+ StandardPlural::Form::TWO,
+ StandardPlural::Form::FEW,
+ StandardPlural::Form::MANY,
+ StandardPlural::Form::OTHER};
+
+ auto pm = new AdoptingModifierStore();
+ if (pm == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+
+ if (needsPlurals()) {
+ // Slower path when we require the plural keyword.
+ for (StandardPlural::Form plural : STANDARD_PLURAL_VALUES) {
+ setNumberProperties(SIGNUM_POS, plural);
+ pm->adoptModifier(SIGNUM_POS, plural, createConstantModifier(status));
+ setNumberProperties(SIGNUM_NEG_ZERO, plural);
+ pm->adoptModifier(SIGNUM_NEG_ZERO, plural, createConstantModifier(status));
+ setNumberProperties(SIGNUM_POS_ZERO, plural);
+ pm->adoptModifier(SIGNUM_POS_ZERO, plural, createConstantModifier(status));
+ setNumberProperties(SIGNUM_NEG, plural);
+ pm->adoptModifier(SIGNUM_NEG, plural, createConstantModifier(status));
+ }
+ if (U_FAILURE(status)) {
+ delete pm;
+ return nullptr;
+ }
+ return new ImmutablePatternModifier(pm, fRules); // adopts pm
+ } else {
+ // Faster path when plural keyword is not needed.
+ setNumberProperties(SIGNUM_POS, StandardPlural::Form::COUNT);
+ pm->adoptModifierWithoutPlural(SIGNUM_POS, createConstantModifier(status));
+ setNumberProperties(SIGNUM_NEG_ZERO, StandardPlural::Form::COUNT);
+ pm->adoptModifierWithoutPlural(SIGNUM_NEG_ZERO, createConstantModifier(status));
+ setNumberProperties(SIGNUM_POS_ZERO, StandardPlural::Form::COUNT);
+ pm->adoptModifierWithoutPlural(SIGNUM_POS_ZERO, createConstantModifier(status));
+ setNumberProperties(SIGNUM_NEG, StandardPlural::Form::COUNT);
+ pm->adoptModifierWithoutPlural(SIGNUM_NEG, createConstantModifier(status));
+ if (U_FAILURE(status)) {
+ delete pm;
+ return nullptr;
+ }
+ return new ImmutablePatternModifier(pm, nullptr); // adopts pm
+ }
+}
+
+ConstantMultiFieldModifier* MutablePatternModifier::createConstantModifier(UErrorCode& status) {
+ FormattedStringBuilder a;
+ FormattedStringBuilder b;
+ insertPrefix(a, 0, status);
+ insertSuffix(b, 0, status);
+ if (fPatternInfo->hasCurrencySign()) {
+ return new CurrencySpacingEnabledModifier(
+ a, b, !fPatternInfo->hasBody(), fStrong, *fSymbols, status);
+ } else {
+ return new ConstantMultiFieldModifier(a, b, !fPatternInfo->hasBody(), fStrong);
+ }
+}
+
+ImmutablePatternModifier::ImmutablePatternModifier(AdoptingModifierStore* pm, const PluralRules* rules)
+ : pm(pm), rules(rules), parent(nullptr) {}
+
+void ImmutablePatternModifier::processQuantity(DecimalQuantity& quantity, MicroProps& micros,
+ UErrorCode& status) const {
+ parent->processQuantity(quantity, micros, status);
+ micros.rounder.apply(quantity, status);
+ if (micros.modMiddle != nullptr) {
+ return;
+ }
+ applyToMicros(micros, quantity, status);
+}
+
+void ImmutablePatternModifier::applyToMicros(
+ MicroProps& micros, const DecimalQuantity& quantity, UErrorCode& status) const {
+ if (rules == nullptr) {
+ micros.modMiddle = pm->getModifierWithoutPlural(quantity.signum());
+ } else {
+ StandardPlural::Form pluralForm = utils::getPluralSafe(micros.rounder, rules, quantity, status);
+ micros.modMiddle = pm->getModifier(quantity.signum(), pluralForm);
+ }
+}
+
+const Modifier* ImmutablePatternModifier::getModifier(Signum signum, StandardPlural::Form plural) const {
+ if (rules == nullptr) {
+ return pm->getModifierWithoutPlural(signum);
+ } else {
+ return pm->getModifier(signum, plural);
+ }
+}
+
+void ImmutablePatternModifier::addToChain(const MicroPropsGenerator* parent) {
+ this->parent = parent;
+}
+
+
+/** Used by the unsafe code path. */
+MicroPropsGenerator& MutablePatternModifier::addToChain(const MicroPropsGenerator* parent) {
+ fParent = parent;
+ return *this;
+}
+
+void MutablePatternModifier::processQuantity(DecimalQuantity& fq, MicroProps& micros,
+ UErrorCode& status) const {
+ fParent->processQuantity(fq, micros, status);
+ micros.rounder.apply(fq, status);
+ if (micros.modMiddle != nullptr) {
+ return;
+ }
+ // 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<MutablePatternModifier*>(this);
+ if (needsPlurals()) {
+ StandardPlural::Form pluralForm = utils::getPluralSafe(micros.rounder, fRules, fq, status);
+ nonConstThis->setNumberProperties(fq.signum(), pluralForm);
+ } else {
+ nonConstThis->setNumberProperties(fq.signum(), StandardPlural::Form::COUNT);
+ }
+ micros.modMiddle = this;
+}
+
+int32_t MutablePatternModifier::apply(FormattedStringBuilder& 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<MutablePatternModifier*>(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 (!fPatternInfo->hasBody()) {
+ overwriteLen = output.splice(
+ leftIndex + prefixLen,
+ rightIndex + prefixLen,
+ UnicodeString(),
+ 0,
+ 0,
+ kUndefinedField,
+ status);
+ }
+ CurrencySpacingEnabledModifier::applyCurrencySpacing(
+ output,
+ leftIndex,
+ prefixLen,
+ rightIndex + overwriteLen + prefixLen,
+ suffixLen,
+ *fSymbols,
+ status);
+ return prefixLen + overwriteLen + suffixLen;
+}
+
+int32_t MutablePatternModifier::getPrefixLength() 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<MutablePatternModifier*>(this);
+
+ // Enter and exit CharSequence Mode to get the length.
+ UErrorCode status = U_ZERO_ERROR; // status fails only with an iilegal argument exception
+ nonConstThis->prepareAffix(true);
+ int result = AffixUtils::unescapedCodePointCount(currentAffix, *this, status); // prefix length
+ return result;
+}
+
+int32_t MutablePatternModifier::getCodePointCount() 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<MutablePatternModifier*>(this);
+
+ // Render the affixes to get the length
+ UErrorCode status = U_ZERO_ERROR; // status fails only with an iilegal argument exception
+ 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;
+}
+
+bool MutablePatternModifier::isStrong() const {
+ return fStrong;
+}
+
+bool MutablePatternModifier::containsField(Field field) const {
+ (void)field;
+ // This method is not currently used.
+ UPRV_UNREACHABLE;
+}
+
+void MutablePatternModifier::getParameters(Parameters& output) const {
+ (void)output;
+ // This method is not currently used.
+ UPRV_UNREACHABLE;
+}
+
+bool MutablePatternModifier::semanticallyEquivalent(const Modifier& other) const {
+ (void)other;
+ // This method is not currently used.
+ UPRV_UNREACHABLE;
+}
+
+int32_t MutablePatternModifier::insertPrefix(FormattedStringBuilder& sb, int position, UErrorCode& status) {
+ prepareAffix(true);
+ int32_t length = AffixUtils::unescape(currentAffix, sb, position, *this, fField, status);
+ return length;
+}
+
+int32_t MutablePatternModifier::insertSuffix(FormattedStringBuilder& sb, int position, UErrorCode& status) {
+ prepareAffix(false);
+ int32_t length = AffixUtils::unescape(currentAffix, sb, position, *this, fField, status);
+ return length;
+}
+
+/** This method contains the heart of the logic for rendering LDML affix strings. */
+void MutablePatternModifier::prepareAffix(bool isPrefix) {
+ PatternStringUtils::patternInfoToStringBuilder(
+ *fPatternInfo,
+ isPrefix,
+ PatternStringUtils::resolveSignDisplay(fSignDisplay, fSignum),
+ fPlural,
+ fPerMilleReplacesPercent,
+ currentAffix);
+}
+
+UnicodeString MutablePatternModifier::getSymbol(AffixPatternType type) const {
+ UErrorCode localStatus = U_ZERO_ERROR;
+ switch (type) {
+ case AffixPatternType::TYPE_MINUS_SIGN:
+ return fSymbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kMinusSignSymbol);
+ case AffixPatternType::TYPE_PLUS_SIGN:
+ return fSymbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPlusSignSymbol);
+ case AffixPatternType::TYPE_PERCENT:
+ return fSymbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPercentSymbol);
+ case AffixPatternType::TYPE_PERMILLE:
+ return fSymbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPerMillSymbol);
+ case AffixPatternType::TYPE_CURRENCY_SINGLE: {
+ // UnitWidth ISO and HIDDEN overrides the singular currency symbol.
+ if (fUnitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE) {
+ return fCurrencySymbols.getIntlCurrencySymbol(localStatus);
+ } else if (fUnitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_HIDDEN) {
+ return UnicodeString();
+ } else if (fUnitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW) {
+ return fCurrencySymbols.getNarrowCurrencySymbol(localStatus);
+ } else {
+ return fCurrencySymbols.getCurrencySymbol(localStatus);
+ }
+ }
+ case AffixPatternType::TYPE_CURRENCY_DOUBLE:
+ return fCurrencySymbols.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(fPlural != StandardPlural::Form::COUNT);
+ return fCurrencySymbols.getPluralName(fPlural, localStatus);
+ case AffixPatternType::TYPE_CURRENCY_QUAD:
+ return UnicodeString(u"\uFFFD");
+ case AffixPatternType::TYPE_CURRENCY_QUINT:
+ return UnicodeString(u"\uFFFD");
+ default:
+ UPRV_UNREACHABLE;
+ }
+}
+
+UnicodeString MutablePatternModifier::toUnicodeString() const {
+ // Never called by AffixUtils
+ UPRV_UNREACHABLE;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_patternmodifier.h b/contrib/libs/icu/i18n/number_patternmodifier.h
index 5ba842d569..9baea472f9 100644
--- a/contrib/libs/icu/i18n/number_patternmodifier.h
+++ b/contrib/libs/icu/i18n/number_patternmodifier.h
@@ -1,254 +1,254 @@
-// © 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_PATTERNMODIFIER_H__
-#define __NUMBER_PATTERNMODIFIER_H__
-
-#include "standardplural.h"
-#include "unicode/numberformatter.h"
-#include "number_patternstring.h"
-#include "number_types.h"
-#include "number_modifiers.h"
-#include "number_utils.h"
-#include "number_currencysymbols.h"
-
-U_NAMESPACE_BEGIN
-
-// Export an explicit template instantiation of the LocalPointer that is used as a
-// data member of AdoptingModifierStore.
-// (When building DLLs for Windows this is required.)
-#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
-#if defined(_MSC_VER)
-// Ignore warning 4661 as LocalPointerBase does not use operator== or operator!=
-#pragma warning(push)
-#pragma warning(disable : 4661)
-#endif
-template class U_I18N_API LocalPointerBase<number::impl::AdoptingModifierStore>;
-template class U_I18N_API LocalPointer<number::impl::AdoptingModifierStore>;
-#if defined(_MSC_VER)
-#pragma warning(pop)
-#endif
-#endif
-
-namespace number {
-namespace impl {
-
-// Forward declaration
-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;
-
- void processQuantity(DecimalQuantity&, MicroProps& micros, UErrorCode& status) const U_OVERRIDE;
-
- void applyToMicros(MicroProps& micros, const DecimalQuantity& quantity, UErrorCode& status) const;
-
- const Modifier* getModifier(Signum signum, StandardPlural::Form plural) const;
-
- // Non-const method:
- void addToChain(const MicroPropsGenerator* parent);
-
- private:
- ImmutablePatternModifier(AdoptingModifierStore* pm, const PluralRules* rules);
-
- const LocalPointer<AdoptingModifierStore> pm;
- const PluralRules* rules;
- const MicroPropsGenerator* parent;
-
- friend class MutablePatternModifier;
-};
-
-/**
- * This class is a {@link Modifier} that wraps a decimal format pattern. It applies the pattern's affixes in
- * {@link Modifier#apply}.
- *
- * <p>
- * In addition to being a Modifier, this class contains the business logic for substituting the correct locale symbols
- * into the affixes of the decimal format pattern.
- *
- * <p>
- * In order to use this class, create a new instance and call the following four setters: {@link #setPatternInfo},
- * {@link #setPatternAttributes}, {@link #setSymbols}, and {@link #setNumberProperties}. After calling these four
- * setters, the instance will be ready for use as a Modifier.
- *
- * <p>
- * This is a MUTABLE, NON-THREAD-SAFE class designed for performance. Do NOT save references to this or attempt to use
- * it from multiple threads! Instead, you can obtain a safe, immutable decimal format pattern modifier by calling
- * {@link MutablePatternModifier#createImmutable}, in effect treating this instance as a builder for the immutable
- * variant.
- */
-class U_I18N_API MutablePatternModifier
- : public MicroPropsGenerator,
- public Modifier,
- public SymbolProvider,
- public UMemory {
- public:
-
- ~MutablePatternModifier() U_OVERRIDE = default;
-
- /**
- * @param isStrong
- * Whether the modifier should be considered strong. For more information, see
- * {@link Modifier#isStrong()}. Most of the time, decimal format pattern modifiers should be considered
- * as non-strong.
- */
- explicit MutablePatternModifier(bool isStrong);
-
- /**
- * Sets a reference to the parsed decimal format pattern, usually obtained from
- * {@link PatternStringParser#parseToPatternInfo(String)}, but any implementation of {@link AffixPatternProvider} is
- * accepted.
- *
- * @param field
- * Which field to use for literal characters in the pattern.
- */
- void setPatternInfo(const AffixPatternProvider *patternInfo, Field field);
-
- /**
- * Sets attributes that imply changes to the literal interpretation of the pattern string affixes.
- *
- * @param signDisplay
- * Whether to force a plus sign on positive numbers.
- * @param perMille
- * Whether to substitute the percent sign in the pattern with a permille sign.
- */
- void setPatternAttributes(UNumberSignDisplay signDisplay, bool perMille);
-
- /**
- * Sets locale-specific details that affect the symbols substituted into the pattern string affixes.
- *
- * @param symbols
- * The desired instance of DecimalFormatSymbols.
- * @param currency
- * The currency 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()}.
- * @param status
- * Set if an error occurs while loading currency data.
- */
- void setSymbols(const DecimalFormatSymbols* symbols, const CurrencyUnit& currency,
- UNumberUnitWidth unitWidth, const PluralRules* rules, UErrorCode& status);
-
- /**
- * Sets attributes of the current number being processed.
- *
- * @param signum
- * -1 if negative; +1 if positive; or 0 if zero.
- * @param plural
- * The plural form of the number, required only if the pattern contains the triple
- * currency sign, "¤¤¤" (and as indicated by {@link #needsPlurals()}).
- */
- void setNumberProperties(Signum signum, StandardPlural::Form plural);
-
- /**
- * Returns true if the pattern represented by this MurkyModifier requires a plural keyword in order to localize.
- * This is currently true only if there is a currency long name placeholder in the pattern ("¤¤¤").
- */
- bool needsPlurals() const;
-
- /**
- * Creates a new quantity-dependent Modifier that behaves the same as the current instance, but which is immutable
- * and can be saved for future use. The number properties in the current instance are mutated; all other properties
- * are left untouched.
- *
- * <p>
- * The resulting modifier cannot be used in a QuantityChain.
- *
- * <p>
- * CREATES A NEW HEAP OBJECT; THE CALLER GETS OWNERSHIP.
- *
- * @return An immutable that supports both positive and negative numbers.
- */
- ImmutablePatternModifier *createImmutable(UErrorCode &status);
-
- MicroPropsGenerator &addToChain(const MicroPropsGenerator *parent);
-
- void processQuantity(DecimalQuantity &, MicroProps &micros, UErrorCode &status) const U_OVERRIDE;
-
- int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
- UErrorCode &status) const U_OVERRIDE;
-
- int32_t getPrefixLength() const U_OVERRIDE;
-
- int32_t getCodePointCount() const U_OVERRIDE;
-
- bool isStrong() const U_OVERRIDE;
-
- bool containsField(Field field) const U_OVERRIDE;
-
- void getParameters(Parameters& output) const U_OVERRIDE;
-
- bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
-
- /**
- * Returns the string that substitutes a given symbol type in a pattern.
- */
- UnicodeString getSymbol(AffixPatternType type) const U_OVERRIDE;
-
- UnicodeString toUnicodeString() const;
-
- private:
- // Modifier details (initialized in constructor)
- const bool fStrong;
-
- // Pattern details (initialized in setPatternInfo and setPatternAttributes)
- const AffixPatternProvider *fPatternInfo;
- Field fField;
- UNumberSignDisplay fSignDisplay;
- bool fPerMilleReplacesPercent;
-
- // Symbol details (initialized in setSymbols)
- const DecimalFormatSymbols *fSymbols;
- UNumberUnitWidth fUnitWidth;
- CurrencySymbols fCurrencySymbols;
- const PluralRules *fRules;
-
- // Number details (initialized in setNumberProperties)
- Signum fSignum;
- StandardPlural::Form fPlural;
-
- // QuantityChain details (initialized in addToChain)
- const MicroPropsGenerator *fParent;
-
- // Transient fields for rendering
- UnicodeString currentAffix;
-
- /**
- * Uses the current properties to create a single {@link ConstantMultiFieldModifier} with currency spacing support
- * if required.
- *
- * <p>
- * CREATES A NEW HEAP OBJECT; THE CALLER GETS OWNERSHIP.
- *
- * @param a
- * A working FormattedStringBuilder object; passed from the outside to prevent the need to create many new
- * instances if this method is called in a loop.
- * @param b
- * Another working FormattedStringBuilder object.
- * @return The constant modifier object.
- */
- ConstantMultiFieldModifier *createConstantModifier(UErrorCode &status);
-
- int32_t insertPrefix(FormattedStringBuilder &sb, int position, UErrorCode &status);
-
- int32_t insertSuffix(FormattedStringBuilder &sb, int position, UErrorCode &status);
-
- void prepareAffix(bool isPrefix);
-};
-
-
-} // namespace impl
-} // namespace number
-U_NAMESPACE_END
-
-#endif //__NUMBER_PATTERNMODIFIER_H__
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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_PATTERNMODIFIER_H__
+#define __NUMBER_PATTERNMODIFIER_H__
+
+#include "standardplural.h"
+#include "unicode/numberformatter.h"
+#include "number_patternstring.h"
+#include "number_types.h"
+#include "number_modifiers.h"
+#include "number_utils.h"
+#include "number_currencysymbols.h"
+
+U_NAMESPACE_BEGIN
+
+// Export an explicit template instantiation of the LocalPointer that is used as a
+// data member of AdoptingModifierStore.
+// (When building DLLs for Windows this is required.)
+#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
+#if defined(_MSC_VER)
+// Ignore warning 4661 as LocalPointerBase does not use operator== or operator!=
+#pragma warning(push)
+#pragma warning(disable : 4661)
+#endif
+template class U_I18N_API LocalPointerBase<number::impl::AdoptingModifierStore>;
+template class U_I18N_API LocalPointer<number::impl::AdoptingModifierStore>;
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+#endif
+
+namespace number {
+namespace impl {
+
+// Forward declaration
+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;
+
+ void processQuantity(DecimalQuantity&, MicroProps& micros, UErrorCode& status) const U_OVERRIDE;
+
+ void applyToMicros(MicroProps& micros, const DecimalQuantity& quantity, UErrorCode& status) const;
+
+ const Modifier* getModifier(Signum signum, StandardPlural::Form plural) const;
+
+ // Non-const method:
+ void addToChain(const MicroPropsGenerator* parent);
+
+ private:
+ ImmutablePatternModifier(AdoptingModifierStore* pm, const PluralRules* rules);
+
+ const LocalPointer<AdoptingModifierStore> pm;
+ const PluralRules* rules;
+ const MicroPropsGenerator* parent;
+
+ friend class MutablePatternModifier;
+};
+
+/**
+ * This class is a {@link Modifier} that wraps a decimal format pattern. It applies the pattern's affixes in
+ * {@link Modifier#apply}.
+ *
+ * <p>
+ * In addition to being a Modifier, this class contains the business logic for substituting the correct locale symbols
+ * into the affixes of the decimal format pattern.
+ *
+ * <p>
+ * In order to use this class, create a new instance and call the following four setters: {@link #setPatternInfo},
+ * {@link #setPatternAttributes}, {@link #setSymbols}, and {@link #setNumberProperties}. After calling these four
+ * setters, the instance will be ready for use as a Modifier.
+ *
+ * <p>
+ * This is a MUTABLE, NON-THREAD-SAFE class designed for performance. Do NOT save references to this or attempt to use
+ * it from multiple threads! Instead, you can obtain a safe, immutable decimal format pattern modifier by calling
+ * {@link MutablePatternModifier#createImmutable}, in effect treating this instance as a builder for the immutable
+ * variant.
+ */
+class U_I18N_API MutablePatternModifier
+ : public MicroPropsGenerator,
+ public Modifier,
+ public SymbolProvider,
+ public UMemory {
+ public:
+
+ ~MutablePatternModifier() U_OVERRIDE = default;
+
+ /**
+ * @param isStrong
+ * Whether the modifier should be considered strong. For more information, see
+ * {@link Modifier#isStrong()}. Most of the time, decimal format pattern modifiers should be considered
+ * as non-strong.
+ */
+ explicit MutablePatternModifier(bool isStrong);
+
+ /**
+ * Sets a reference to the parsed decimal format pattern, usually obtained from
+ * {@link PatternStringParser#parseToPatternInfo(String)}, but any implementation of {@link AffixPatternProvider} is
+ * accepted.
+ *
+ * @param field
+ * Which field to use for literal characters in the pattern.
+ */
+ void setPatternInfo(const AffixPatternProvider *patternInfo, Field field);
+
+ /**
+ * Sets attributes that imply changes to the literal interpretation of the pattern string affixes.
+ *
+ * @param signDisplay
+ * Whether to force a plus sign on positive numbers.
+ * @param perMille
+ * Whether to substitute the percent sign in the pattern with a permille sign.
+ */
+ void setPatternAttributes(UNumberSignDisplay signDisplay, bool perMille);
+
+ /**
+ * Sets locale-specific details that affect the symbols substituted into the pattern string affixes.
+ *
+ * @param symbols
+ * The desired instance of DecimalFormatSymbols.
+ * @param currency
+ * The currency 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()}.
+ * @param status
+ * Set if an error occurs while loading currency data.
+ */
+ void setSymbols(const DecimalFormatSymbols* symbols, const CurrencyUnit& currency,
+ UNumberUnitWidth unitWidth, const PluralRules* rules, UErrorCode& status);
+
+ /**
+ * Sets attributes of the current number being processed.
+ *
+ * @param signum
+ * -1 if negative; +1 if positive; or 0 if zero.
+ * @param plural
+ * The plural form of the number, required only if the pattern contains the triple
+ * currency sign, "¤¤¤" (and as indicated by {@link #needsPlurals()}).
+ */
+ void setNumberProperties(Signum signum, StandardPlural::Form plural);
+
+ /**
+ * Returns true if the pattern represented by this MurkyModifier requires a plural keyword in order to localize.
+ * This is currently true only if there is a currency long name placeholder in the pattern ("¤¤¤").
+ */
+ bool needsPlurals() const;
+
+ /**
+ * Creates a new quantity-dependent Modifier that behaves the same as the current instance, but which is immutable
+ * and can be saved for future use. The number properties in the current instance are mutated; all other properties
+ * are left untouched.
+ *
+ * <p>
+ * The resulting modifier cannot be used in a QuantityChain.
+ *
+ * <p>
+ * CREATES A NEW HEAP OBJECT; THE CALLER GETS OWNERSHIP.
+ *
+ * @return An immutable that supports both positive and negative numbers.
+ */
+ ImmutablePatternModifier *createImmutable(UErrorCode &status);
+
+ MicroPropsGenerator &addToChain(const MicroPropsGenerator *parent);
+
+ void processQuantity(DecimalQuantity &, MicroProps &micros, UErrorCode &status) const U_OVERRIDE;
+
+ int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
+ UErrorCode &status) const U_OVERRIDE;
+
+ int32_t getPrefixLength() const U_OVERRIDE;
+
+ int32_t getCodePointCount() const U_OVERRIDE;
+
+ bool isStrong() const U_OVERRIDE;
+
+ bool containsField(Field field) const U_OVERRIDE;
+
+ void getParameters(Parameters& output) const U_OVERRIDE;
+
+ bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
+
+ /**
+ * Returns the string that substitutes a given symbol type in a pattern.
+ */
+ UnicodeString getSymbol(AffixPatternType type) const U_OVERRIDE;
+
+ UnicodeString toUnicodeString() const;
+
+ private:
+ // Modifier details (initialized in constructor)
+ const bool fStrong;
+
+ // Pattern details (initialized in setPatternInfo and setPatternAttributes)
+ const AffixPatternProvider *fPatternInfo;
+ Field fField;
+ UNumberSignDisplay fSignDisplay;
+ bool fPerMilleReplacesPercent;
+
+ // Symbol details (initialized in setSymbols)
+ const DecimalFormatSymbols *fSymbols;
+ UNumberUnitWidth fUnitWidth;
+ CurrencySymbols fCurrencySymbols;
+ const PluralRules *fRules;
+
+ // Number details (initialized in setNumberProperties)
+ Signum fSignum;
+ StandardPlural::Form fPlural;
+
+ // QuantityChain details (initialized in addToChain)
+ const MicroPropsGenerator *fParent;
+
+ // Transient fields for rendering
+ UnicodeString currentAffix;
+
+ /**
+ * Uses the current properties to create a single {@link ConstantMultiFieldModifier} with currency spacing support
+ * if required.
+ *
+ * <p>
+ * CREATES A NEW HEAP OBJECT; THE CALLER GETS OWNERSHIP.
+ *
+ * @param a
+ * A working FormattedStringBuilder object; passed from the outside to prevent the need to create many new
+ * instances if this method is called in a loop.
+ * @param b
+ * Another working FormattedStringBuilder object.
+ * @return The constant modifier object.
+ */
+ ConstantMultiFieldModifier *createConstantModifier(UErrorCode &status);
+
+ int32_t insertPrefix(FormattedStringBuilder &sb, int position, UErrorCode &status);
+
+ int32_t insertSuffix(FormattedStringBuilder &sb, int position, UErrorCode &status);
+
+ void prepareAffix(bool isPrefix);
+};
+
+
+} // namespace impl
+} // namespace number
+U_NAMESPACE_END
+
+#endif //__NUMBER_PATTERNMODIFIER_H__
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_patternstring.cpp b/contrib/libs/icu/i18n/number_patternstring.cpp
index 9d84505606..0c5ea50c42 100644
--- a/contrib/libs/icu/i18n/number_patternstring.cpp
+++ b/contrib/libs/icu/i18n/number_patternstring.cpp
@@ -1,1120 +1,1120 @@
-// © 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
-
-// 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"
-#include "number_mapper.h"
-
-using namespace icu;
-using namespace icu::number;
-using namespace icu::number::impl;
-
-
-void PatternParser::parseToPatternInfo(const UnicodeString& patternString, ParsedPatternInfo& patternInfo,
- UErrorCode& status) {
- patternInfo.consumePattern(patternString, status);
-}
-
-DecimalFormatProperties
-PatternParser::parseToProperties(const UnicodeString& pattern, IgnoreRounding ignoreRounding,
- UErrorCode& status) {
- DecimalFormatProperties properties;
- parseToExistingPropertiesImpl(pattern, properties, ignoreRounding, status);
- return properties;
-}
-
-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);
- if (index < 0 || index >= endpoints.end - endpoints.start) {
- UPRV_UNREACHABLE;
- }
- return pattern.charAt(endpoints.start + index);
-}
-
-int32_t ParsedPatternInfo::length(int32_t flags) const {
- return getLengthFromEndpoints(getEndpoints(flags));
-}
-
-int32_t ParsedPatternInfo::getLengthFromEndpoints(const Endpoints& endpoints) {
- return endpoints.end - endpoints.start;
-}
-
-UnicodeString ParsedPatternInfo::getString(int32_t flags) const {
- const Endpoints& endpoints = getEndpoints(flags);
- if (endpoints.start == endpoints.end) {
- return UnicodeString();
- }
- // Create a new UnicodeString
- return UnicodeString(pattern, endpoints.start, endpoints.end - endpoints.start);
-}
-
-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;
- if (isNegative && padding) {
- return negative.paddingEndpoints;
- } else if (padding) {
- return positive.paddingEndpoints;
- } else if (prefix && isNegative) {
- return negative.prefixEndpoints;
- } else if (prefix) {
- return positive.prefixEndpoints;
- } else if (isNegative) {
- return negative.suffixEndpoints;
- } else {
- return positive.suffixEndpoints;
- }
-}
-
-bool ParsedPatternInfo::positiveHasPlusSign() const {
- return positive.hasPlusSign;
-}
-
-bool ParsedPatternInfo::hasNegativeSubpattern() const {
- return fHasNegativeSubpattern;
-}
-
-bool ParsedPatternInfo::negativeHasMinusSign() const {
- return negative.hasMinusSign;
-}
-
-bool ParsedPatternInfo::hasCurrencySign() const {
- return positive.hasCurrencySign || (fHasNegativeSubpattern && negative.hasCurrencySign);
-}
-
-bool ParsedPatternInfo::containsSymbolType(AffixPatternType type, UErrorCode& status) const {
- return AffixUtils::containsType(pattern, type, status);
-}
-
-bool ParsedPatternInfo::hasBody() const {
- return positive.integerTotal > 0;
-}
-
-/////////////////////////////////////////////////////
-/// BEGIN RECURSIVE DESCENT PARSER IMPLEMENTATION ///
-/////////////////////////////////////////////////////
-
-UChar32 ParsedPatternInfo::ParserState::peek() {
- if (offset == pattern.length()) {
- return -1;
- } else {
- return pattern.char32At(offset);
- }
-}
-
-UChar32 ParsedPatternInfo::ParserState::next() {
- int codePoint = peek();
- offset += U16_LENGTH(codePoint);
- return codePoint;
-}
-
-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);
- if (U_FAILURE(status)) { return; }
- if (state.peek() == u';') {
- state.next(); // consume the ';'
- // Don't consume the negative subpattern if it is empty (trailing ';')
- if (state.peek() != -1) {
- fHasNegativeSubpattern = true;
- currentSubpattern = &negative;
- consumeSubpattern(status);
- if (U_FAILURE(status)) { return; }
- }
- }
- if (state.peek() != -1) {
- state.toParseException(u"Found unquoted special character");
- status = U_UNQUOTED_SPECIAL;
- }
-}
-
-void ParsedPatternInfo::consumeSubpattern(UErrorCode& status) {
- // subpattern := literals? number exponent? literals?
- consumePadding(PadPosition::UNUM_PAD_BEFORE_PREFIX, status);
- if (U_FAILURE(status)) { return; }
- consumeAffix(currentSubpattern->prefixEndpoints, status);
- if (U_FAILURE(status)) { return; }
- consumePadding(PadPosition::UNUM_PAD_AFTER_PREFIX, status);
- if (U_FAILURE(status)) { return; }
- consumeFormat(status);
- if (U_FAILURE(status)) { return; }
- consumeExponent(status);
- if (U_FAILURE(status)) { return; }
- consumePadding(PadPosition::UNUM_PAD_BEFORE_SUFFIX, status);
- if (U_FAILURE(status)) { return; }
- consumeAffix(currentSubpattern->suffixEndpoints, status);
- if (U_FAILURE(status)) { return; }
- consumePadding(PadPosition::UNUM_PAD_AFTER_SUFFIX, status);
- if (U_FAILURE(status)) { return; }
-}
-
-void ParsedPatternInfo::consumePadding(PadPosition paddingLocation, UErrorCode& status) {
- if (state.peek() != u'*') {
- return;
- }
- 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) {
- // literals := { literal }
- endpoints.start = state.offset;
- while (true) {
- switch (state.peek()) {
- case u'#':
- case u'@':
- case u';':
- case u'*':
- case u'.':
- case u',':
- case u'0':
- case u'1':
- case u'2':
- case u'3':
- case u'4':
- case u'5':
- case u'6':
- case u'7':
- case u'8':
- case u'9':
- case -1:
- // Characters that cannot appear unquoted in a literal
- // break outer;
- goto after_outer;
-
- case u'%':
- currentSubpattern->hasPercentSign = true;
- break;
-
- case u'‰':
- currentSubpattern->hasPerMilleSign = true;
- break;
-
- case u'¤':
- currentSubpattern->hasCurrencySign = true;
- break;
-
- case u'-':
- currentSubpattern->hasMinusSign = true;
- break;
-
- case u'+':
- currentSubpattern->hasPlusSign = true;
- break;
-
- default:
- break;
- }
- consumeLiteral(status);
- if (U_FAILURE(status)) { return; }
- }
- after_outer:
- endpoints.end = state.offset;
-}
-
-void ParsedPatternInfo::consumeLiteral(UErrorCode& status) {
- if (state.peek() == -1) {
- state.toParseException(u"Expected unquoted literal but found EOL");
- status = U_PATTERN_SYNTAX_ERROR;
- return;
- } else if (state.peek() == u'\'') {
- state.next(); // consume the starting quote
- while (state.peek() != u'\'') {
- if (state.peek() == -1) {
- state.toParseException(u"Expected quoted literal but found EOL");
- status = U_PATTERN_SYNTAX_ERROR;
- return;
- } else {
- state.next(); // consume a quoted character
- }
- }
- state.next(); // consume the ending quote
- } else {
- // consume a non-quoted literal character
- state.next();
- }
-}
-
-void ParsedPatternInfo::consumeFormat(UErrorCode& status) {
- consumeIntegerFormat(status);
- if (U_FAILURE(status)) { return; }
- if (state.peek() == u'.') {
- state.next(); // consume the decimal point
- currentSubpattern->hasDecimal = true;
- currentSubpattern->widthExceptAffixes += 1;
- consumeFractionFormat(status);
- if (U_FAILURE(status)) { return; }
- }
-}
-
-void ParsedPatternInfo::consumeIntegerFormat(UErrorCode& status) {
- // Convenience reference:
- ParsedSubpatternInfo& result = *currentSubpattern;
-
- while (true) {
- switch (state.peek()) {
- case u',':
- result.widthExceptAffixes += 1;
- result.groupingSizes <<= 16;
- break;
-
- case u'#':
- if (result.integerNumerals > 0) {
- state.toParseException(u"# cannot follow 0 before decimal point");
- status = U_UNEXPECTED_TOKEN;
- return;
- }
- result.widthExceptAffixes += 1;
- result.groupingSizes += 1;
- if (result.integerAtSigns > 0) {
- result.integerTrailingHashSigns += 1;
- } else {
- result.integerLeadingHashSigns += 1;
- }
- result.integerTotal += 1;
- break;
-
- case u'@':
- if (result.integerNumerals > 0) {
- state.toParseException(u"Cannot mix 0 and @");
- status = U_UNEXPECTED_TOKEN;
- return;
- }
- if (result.integerTrailingHashSigns > 0) {
- state.toParseException(u"Cannot nest # inside of a run of @");
- status = U_UNEXPECTED_TOKEN;
- return;
- }
- result.widthExceptAffixes += 1;
- result.groupingSizes += 1;
- result.integerAtSigns += 1;
- result.integerTotal += 1;
- break;
-
- case u'0':
- case u'1':
- case u'2':
- case u'3':
- case u'4':
- case u'5':
- case u'6':
- case u'7':
- case u'8':
- case u'9':
- if (result.integerAtSigns > 0) {
- state.toParseException(u"Cannot mix @ and 0");
- status = U_UNEXPECTED_TOKEN;
- return;
- }
- result.widthExceptAffixes += 1;
- result.groupingSizes += 1;
- result.integerNumerals += 1;
- result.integerTotal += 1;
- if (!result.rounding.isZeroish() || state.peek() != u'0') {
- result.rounding.appendDigit(static_cast<int8_t>(state.peek() - u'0'), 0, true);
- }
- break;
-
- default:
- goto after_outer;
- }
- state.next(); // consume the symbol
- }
-
- after_outer:
- // Disallow patterns with a trailing ',' or with two ',' next to each other
- auto grouping1 = static_cast<int16_t> (result.groupingSizes & 0xffff);
- auto grouping2 = static_cast<int16_t> ((result.groupingSizes >> 16) & 0xffff);
- auto grouping3 = static_cast<int16_t> ((result.groupingSizes >> 32) & 0xffff);
- if (grouping1 == 0 && grouping2 != -1) {
- state.toParseException(u"Trailing grouping separator is invalid");
- status = U_UNEXPECTED_TOKEN;
- return;
- }
- if (grouping2 == 0 && grouping3 != -1) {
- state.toParseException(u"Grouping width of zero is invalid");
- status = U_PATTERN_SYNTAX_ERROR;
- return;
- }
-}
-
-void ParsedPatternInfo::consumeFractionFormat(UErrorCode& status) {
- // Convenience reference:
- ParsedSubpatternInfo& result = *currentSubpattern;
-
- int32_t zeroCounter = 0;
- while (true) {
- switch (state.peek()) {
- case u'#':
- result.widthExceptAffixes += 1;
- result.fractionHashSigns += 1;
- result.fractionTotal += 1;
- zeroCounter++;
- break;
-
- case u'0':
- case u'1':
- case u'2':
- case u'3':
- case u'4':
- case u'5':
- case u'6':
- case u'7':
- case u'8':
- case u'9':
- if (result.fractionHashSigns > 0) {
- state.toParseException(u"0 cannot follow # after decimal point");
- status = U_UNEXPECTED_TOKEN;
- return;
- }
- result.widthExceptAffixes += 1;
- result.fractionNumerals += 1;
- result.fractionTotal += 1;
- if (state.peek() == u'0') {
- zeroCounter++;
- } else {
- result.rounding
- .appendDigit(static_cast<int8_t>(state.peek() - u'0'), zeroCounter, false);
- zeroCounter = 0;
- }
- break;
-
- default:
- return;
- }
- state.next(); // consume the symbol
- }
-}
-
-void ParsedPatternInfo::consumeExponent(UErrorCode& status) {
- // Convenience reference:
- ParsedSubpatternInfo& result = *currentSubpattern;
-
- if (state.peek() != u'E') {
- return;
- }
- if ((result.groupingSizes & 0xffff0000L) != 0xffff0000L) {
- state.toParseException(u"Cannot have grouping separator in scientific notation");
- status = U_MALFORMED_EXPONENTIAL_PATTERN;
- return;
- }
- state.next(); // consume the E
- result.widthExceptAffixes++;
- if (state.peek() == u'+') {
- state.next(); // consume the +
- result.exponentHasPlusSign = true;
- result.widthExceptAffixes++;
- }
- while (state.peek() == u'0') {
- state.next(); // consume the 0
- result.exponentZeros += 1;
- result.widthExceptAffixes++;
- }
-}
-
-///////////////////////////////////////////////////
-/// END RECURSIVE DESCENT PARSER IMPLEMENTATION ///
-///////////////////////////////////////////////////
-
-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?
- properties.clear();
- return;
- }
-
- ParsedPatternInfo patternInfo;
- parseToPatternInfo(pattern, patternInfo, status);
- if (U_FAILURE(status)) { return; }
- patternInfoToProperties(properties, patternInfo, ignoreRounding, 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;
-
- bool ignoreRounding;
- if (_ignoreRounding == IGNORE_ROUNDING_NEVER) {
- ignoreRounding = false;
- } else if (_ignoreRounding == IGNORE_ROUNDING_IF_CURRENCY) {
- ignoreRounding = positive.hasCurrencySign;
- } else {
- U_ASSERT(_ignoreRounding == IGNORE_ROUNDING_ALWAYS);
- ignoreRounding = true;
- }
-
- // Grouping settings
- auto grouping1 = static_cast<int16_t> (positive.groupingSizes & 0xffff);
- auto grouping2 = static_cast<int16_t> ((positive.groupingSizes >> 16) & 0xffff);
- auto grouping3 = static_cast<int16_t> ((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;
- } else {
- properties.secondaryGroupingSize = -1;
- }
-
- // For backwards compatibility, require that the pattern emit at least one min digit.
- int minInt, minFrac;
- if (positive.integerTotal == 0 && positive.fractionTotal > 0) {
- // patterns like ".##"
- minInt = 0;
- minFrac = uprv_max(1, positive.fractionNumerals);
- } else if (positive.integerNumerals == 0 && positive.fractionNumerals == 0) {
- // patterns like "#.##"
- minInt = 1;
- minFrac = 0;
- } else {
- minInt = positive.integerNumerals;
- minFrac = positive.fractionNumerals;
- }
-
- // Rounding settings
- // Don't set basic rounding when there is a currency sign; defer to CurrencyUsage
- if (positive.integerAtSigns > 0) {
- properties.minimumFractionDigits = -1;
- properties.maximumFractionDigits = -1;
- properties.roundingIncrement = 0.0;
- properties.minimumSignificantDigits = positive.integerAtSigns;
- properties.maximumSignificantDigits = positive.integerAtSigns + positive.integerTrailingHashSigns;
- } else if (!positive.rounding.isZeroish()) {
- if (!ignoreRounding) {
- properties.minimumFractionDigits = minFrac;
- properties.maximumFractionDigits = positive.fractionTotal;
- properties.roundingIncrement = positive.rounding.toDouble();
- } else {
- properties.minimumFractionDigits = -1;
- properties.maximumFractionDigits = -1;
- properties.roundingIncrement = 0.0;
- }
- properties.minimumSignificantDigits = -1;
- properties.maximumSignificantDigits = -1;
- } else {
- if (!ignoreRounding) {
- properties.minimumFractionDigits = minFrac;
- properties.maximumFractionDigits = positive.fractionTotal;
- properties.roundingIncrement = 0.0;
- } else {
- properties.minimumFractionDigits = -1;
- properties.maximumFractionDigits = -1;
- properties.roundingIncrement = 0.0;
- }
- properties.minimumSignificantDigits = -1;
- properties.maximumSignificantDigits = -1;
- }
-
- // If the pattern ends with a '.' then force the decimal point.
- if (positive.hasDecimal && positive.fractionTotal == 0) {
- properties.decimalSeparatorAlwaysShown = true;
- } else {
- properties.decimalSeparatorAlwaysShown = false;
- }
-
- // Scientific notation settings
- if (positive.exponentZeros > 0) {
- properties.exponentSignAlwaysShown = positive.exponentHasPlusSign;
- properties.minimumExponentDigits = positive.exponentZeros;
- if (positive.integerAtSigns == 0) {
- // patterns without '@' can define max integer digits, used for engineering notation
- properties.minimumIntegerDigits = positive.integerNumerals;
- properties.maximumIntegerDigits = positive.integerTotal;
- } else {
- // patterns with '@' cannot define max integer digits
- properties.minimumIntegerDigits = 1;
- properties.maximumIntegerDigits = -1;
- }
- } else {
- properties.exponentSignAlwaysShown = false;
- properties.minimumExponentDigits = -1;
- properties.minimumIntegerDigits = minInt;
- properties.maximumIntegerDigits = -1;
- }
-
- // Compute the affix patterns (required for both padding and affixes)
- UnicodeString posPrefix = patternInfo.getString(AffixPatternProvider::AFFIX_PREFIX);
- UnicodeString posSuffix = patternInfo.getString(0);
-
- // Padding settings
- if (positive.hasPadding) {
- // The width of the positive prefix and suffix templates are included in the padding
- 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) {
- properties.padString = rawPaddingString;
- } else if (rawPaddingString.length() == 2) {
- if (rawPaddingString.charAt(0) == u'\'') {
- properties.padString.setTo(u"'", -1);
- } else {
- properties.padString = rawPaddingString;
- }
- } else {
- properties.padString = UnicodeString(rawPaddingString, 1, rawPaddingString.length() - 2);
- }
- properties.padPosition = positive.paddingLocation;
- } else {
- properties.formatWidth = -1;
- properties.padString.setToBogus();
- properties.padPosition.nullify();
- }
-
- // Set the affixes
- // Always call the setter, even if the prefixes are empty, especially in the case of the
- // negative prefix pattern, to prevent default values from overriding the pattern.
- properties.positivePrefixPattern = posPrefix;
- properties.positiveSuffixPattern = posSuffix;
- if (patternInfo.fHasNegativeSubpattern) {
- properties.negativePrefixPattern = patternInfo.getString(
- AffixPatternProvider::AFFIX_NEGATIVE_SUBPATTERN | AffixPatternProvider::AFFIX_PREFIX);
- properties.negativeSuffixPattern = patternInfo.getString(
- AffixPatternProvider::AFFIX_NEGATIVE_SUBPATTERN);
- } else {
- properties.negativePrefixPattern.setToBogus();
- properties.negativeSuffixPattern.setToBogus();
- }
-
- // Set the magnitude multiplier
- if (positive.hasPercentSign) {
- properties.magnitudeMultiplier = 2;
- } else if (positive.hasPerMilleSign) {
- properties.magnitudeMultiplier = 3;
- } else {
- properties.magnitudeMultiplier = 0;
- }
-}
-
-///////////////////////////////////////////////////////////////////
-/// End PatternStringParser.java; begin PatternStringUtils.java ///
-///////////////////////////////////////////////////////////////////
-
-// Determine whether a given roundingIncrement should be ignored for formatting
-// based on the current maxFrac value (maximum fraction digits). For example a
-// roundingIncrement of 0.01 should be ignored if maxFrac is 1, but not if maxFrac
-// is 2 or more. Note that roundingIncrements are rounded in significance, so
-// a roundingIncrement of 0.006 is treated like 0.01 for this determination, i.e.
-// it should not be ignored if maxFrac is 2 or more (but a roundingIncrement of
-// 0.005 is treated like 0.001 for significance). This is the reason for the
-// initial doubling below.
-// roundIncr must be non-zero.
-bool PatternStringUtils::ignoreRoundingIncrement(double roundIncr, int32_t maxFrac) {
- if (maxFrac < 0) {
- return false;
- }
- int32_t frac = 0;
- roundIncr *= 2.0;
- for (frac = 0; frac <= maxFrac && roundIncr <= 1.0; frac++, roundIncr *= 10.0);
- return (frac > maxFrac);
-}
-
-UnicodeString PatternStringUtils::propertiesToPatternString(const DecimalFormatProperties& properties,
- UErrorCode& status) {
- UnicodeString sb;
-
- // Convenience references
- // The uprv_min() calls prevent DoS
- int32_t dosMax = 100;
- int32_t grouping1 = uprv_max(0, uprv_min(properties.groupingSize, dosMax));
- int32_t grouping2 = uprv_max(0, uprv_min(properties.secondaryGroupingSize, dosMax));
- bool useGrouping = properties.groupingUsed;
- int32_t paddingWidth = uprv_min(properties.formatWidth, dosMax);
- NullableValue<PadPosition> paddingLocation = properties.padPosition;
- UnicodeString paddingString = properties.padString;
- int32_t minInt = uprv_max(0, uprv_min(properties.minimumIntegerDigits, dosMax));
- int32_t maxInt = uprv_min(properties.maximumIntegerDigits, dosMax);
- int32_t minFrac = uprv_max(0, uprv_min(properties.minimumFractionDigits, dosMax));
- int32_t maxFrac = uprv_min(properties.maximumFractionDigits, dosMax);
- int32_t minSig = uprv_min(properties.minimumSignificantDigits, dosMax);
- int32_t maxSig = uprv_min(properties.maximumSignificantDigits, dosMax);
- bool alwaysShowDecimal = properties.decimalSeparatorAlwaysShown;
- int32_t exponentDigits = uprv_min(properties.minimumExponentDigits, dosMax);
- bool exponentShowPlusSign = properties.exponentSignAlwaysShown;
-
- AutoAffixPatternProvider affixProvider(properties, status);
-
- // Prefixes
- sb.append(affixProvider.get().getString(AffixPatternProvider::AFFIX_POS_PREFIX));
- int32_t afterPrefixPos = sb.length();
-
- // Figure out the grouping sizes.
- if (!useGrouping) {
- grouping1 = 0;
- grouping2 = 0;
- } else if (grouping1 == grouping2) {
- grouping1 = 0;
- }
- int32_t groupingLength = grouping1 + grouping2 + 1;
-
- // Figure out the digits we need to put in the pattern.
- double roundingInterval = properties.roundingIncrement;
- UnicodeString digitsString;
- int32_t digitsStringScale = 0;
- if (maxSig != uprv_min(dosMax, -1)) {
- // Significant Digits.
- while (digitsString.length() < minSig) {
- digitsString.append(u'@');
- }
- while (digitsString.length() < maxSig) {
- digitsString.append(u'#');
- }
- } else if (roundingInterval != 0.0 && !ignoreRoundingIncrement(roundingInterval,maxFrac)) {
- // Rounding Interval.
- digitsStringScale = -roundingutils::doubleFractionLength(roundingInterval, nullptr);
- // TODO: Check for DoS here?
- DecimalQuantity incrementQuantity;
- incrementQuantity.setToDouble(roundingInterval);
- incrementQuantity.adjustMagnitude(-digitsStringScale);
- incrementQuantity.roundToMagnitude(0, kDefaultMode, status);
- UnicodeString str = incrementQuantity.toPlainString();
- if (str.charAt(0) == u'-') {
- // TODO: Unsupported operation exception or fail silently?
- digitsString.append(str, 1, str.length() - 1);
- } else {
- digitsString.append(str);
- }
- }
- while (digitsString.length() + digitsStringScale < minInt) {
- digitsString.insert(0, u'0');
- }
- while (-digitsStringScale < minFrac) {
- digitsString.append(u'0');
- digitsStringScale--;
- }
-
- // Write the digits to the string builder
- int32_t m0 = uprv_max(groupingLength, digitsString.length() + digitsStringScale);
- m0 = (maxInt != dosMax) ? uprv_max(maxInt, m0) - 1 : m0 - 1;
- int32_t mN = (maxFrac != dosMax) ? uprv_min(-maxFrac, digitsStringScale) : digitsStringScale;
- for (int32_t magnitude = m0; magnitude >= mN; magnitude--) {
- int32_t di = digitsString.length() + digitsStringScale - magnitude - 1;
- if (di < 0 || di >= digitsString.length()) {
- sb.append(u'#');
- } else {
- sb.append(digitsString.charAt(di));
- }
- // Decimal separator
- if (magnitude == 0 && (alwaysShowDecimal || mN < 0)) {
- sb.append(u'.');
- }
- if (!useGrouping) {
- continue;
- }
- // Least-significant grouping separator
- if (magnitude > 0 && magnitude == grouping1) {
- sb.append(u',');
- }
- // All other grouping separators
- if (magnitude > grouping1 && grouping2 > 0 && (magnitude - grouping1) % grouping2 == 0) {
- sb.append(u',');
- }
- }
-
- // Exponential notation
- if (exponentDigits != uprv_min(dosMax, -1)) {
- sb.append(u'E');
- if (exponentShowPlusSign) {
- sb.append(u'+');
- }
- for (int32_t i = 0; i < exponentDigits; i++) {
- sb.append(u'0');
- }
- }
-
- // Suffixes
- int32_t beforeSuffixPos = sb.length();
- sb.append(affixProvider.get().getString(AffixPatternProvider::AFFIX_POS_SUFFIX));
-
- // Resolve Padding
- if (paddingWidth > 0 && !paddingLocation.isNull()) {
- while (paddingWidth - sb.length() > 0) {
- sb.insert(afterPrefixPos, u'#');
- beforeSuffixPos++;
- }
- int32_t addedLength;
- switch (paddingLocation.get(status)) {
- case PadPosition::UNUM_PAD_BEFORE_PREFIX:
- addedLength = escapePaddingString(paddingString, sb, 0, status);
- sb.insert(0, u'*');
- afterPrefixPos += addedLength + 1;
- beforeSuffixPos += addedLength + 1;
- break;
- case PadPosition::UNUM_PAD_AFTER_PREFIX:
- addedLength = escapePaddingString(paddingString, sb, afterPrefixPos, status);
- sb.insert(afterPrefixPos, u'*');
- afterPrefixPos += addedLength + 1;
- beforeSuffixPos += addedLength + 1;
- break;
- case PadPosition::UNUM_PAD_BEFORE_SUFFIX:
- escapePaddingString(paddingString, sb, beforeSuffixPos, status);
- sb.insert(beforeSuffixPos, u'*');
- break;
- case PadPosition::UNUM_PAD_AFTER_SUFFIX:
- sb.append(u'*');
- escapePaddingString(paddingString, sb, sb.length(), status);
- break;
- }
- if (U_FAILURE(status)) { return sb; }
- }
-
- // Negative affixes
- // Ignore if the negative prefix pattern is "-" and the negative suffix is empty
- if (affixProvider.get().hasNegativeSubpattern()) {
- sb.append(u';');
- sb.append(affixProvider.get().getString(AffixPatternProvider::AFFIX_NEG_PREFIX));
- // Copy the positive digit format into the negative.
- // This is optional; the pattern is the same as if '#' were appended here instead.
- // 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);
- sb.append(affixProvider.get().getString(AffixPatternProvider::AFFIX_NEG_SUFFIX));
- }
-
- return sb;
-}
-
-int PatternStringUtils::escapePaddingString(UnicodeString input, UnicodeString& output, int startIndex,
- UErrorCode& status) {
- (void) status;
- if (input.length() == 0) {
- input.setTo(kFallbackPaddingString, -1);
- }
- int startLength = output.length();
- if (input.length() == 1) {
- if (input.compare(u"'", -1) == 0) {
- output.insert(startIndex, u"''", -1);
- } else {
- output.insert(startIndex, input);
- }
- } else {
- output.insert(startIndex, u'\'');
- int offset = 1;
- for (int i = 0; i < input.length(); i++) {
- // it's okay to deal in chars here because the quote mark is the only interesting thing.
- char16_t ch = input.charAt(i);
- if (ch == u'\'') {
- output.insert(startIndex + offset, u"''", -1);
- offset += 2;
- } else {
- output.insert(startIndex + offset, ch);
- offset += 1;
- }
- }
- output.insert(startIndex + offset, u'\'');
- }
- 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,
- PatternSignType patternSignType,
- StandardPlural::Form plural,
- bool perMilleReplacesPercent, UnicodeString& output) {
-
- // Should the output render '+' where '-' would normally appear in the pattern?
- bool plusReplacesMinusSign = (patternSignType == PATTERN_SIGN_TYPE_POS_SIGN)
- && !patternInfo.positiveHasPlusSign();
-
- // Should we use the affix from the negative subpattern?
- // (If not, we will use the positive subpattern.)
- bool useNegativeAffixPattern = patternInfo.hasNegativeSubpattern()
- && (patternSignType == PATTERN_SIGN_TYPE_NEG
- || (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 (patternSignType == PATTERN_SIGN_TYPE_NEG) {
- prependSign = true;
- } 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);
- }
-}
-
-PatternSignType PatternStringUtils::resolveSignDisplay(UNumberSignDisplay signDisplay, Signum signum) {
- switch (signDisplay) {
- case UNUM_SIGN_AUTO:
- case UNUM_SIGN_ACCOUNTING:
- switch (signum) {
- case SIGNUM_NEG:
- case SIGNUM_NEG_ZERO:
- return PATTERN_SIGN_TYPE_NEG;
- case SIGNUM_POS_ZERO:
- case SIGNUM_POS:
- return PATTERN_SIGN_TYPE_POS;
- default:
- break;
- }
- break;
-
- case UNUM_SIGN_ALWAYS:
- case UNUM_SIGN_ACCOUNTING_ALWAYS:
- switch (signum) {
- case SIGNUM_NEG:
- case SIGNUM_NEG_ZERO:
- return PATTERN_SIGN_TYPE_NEG;
- case SIGNUM_POS_ZERO:
- case SIGNUM_POS:
- return PATTERN_SIGN_TYPE_POS_SIGN;
- default:
- break;
- }
- break;
-
- case UNUM_SIGN_EXCEPT_ZERO:
- case UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO:
- switch (signum) {
- case SIGNUM_NEG:
- return PATTERN_SIGN_TYPE_NEG;
- case SIGNUM_NEG_ZERO:
- case SIGNUM_POS_ZERO:
- return PATTERN_SIGN_TYPE_POS;
- case SIGNUM_POS:
- return PATTERN_SIGN_TYPE_POS_SIGN;
- default:
- break;
- }
- break;
-
- case UNUM_SIGN_NEVER:
- return PATTERN_SIGN_TYPE_POS;
-
- default:
- break;
- }
-
- UPRV_UNREACHABLE;
- return PATTERN_SIGN_TYPE_POS;
-}
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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
+
+// 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"
+#include "number_mapper.h"
+
+using namespace icu;
+using namespace icu::number;
+using namespace icu::number::impl;
+
+
+void PatternParser::parseToPatternInfo(const UnicodeString& patternString, ParsedPatternInfo& patternInfo,
+ UErrorCode& status) {
+ patternInfo.consumePattern(patternString, status);
+}
+
+DecimalFormatProperties
+PatternParser::parseToProperties(const UnicodeString& pattern, IgnoreRounding ignoreRounding,
+ UErrorCode& status) {
+ DecimalFormatProperties properties;
+ parseToExistingPropertiesImpl(pattern, properties, ignoreRounding, status);
+ return properties;
+}
+
+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);
+ if (index < 0 || index >= endpoints.end - endpoints.start) {
+ UPRV_UNREACHABLE;
+ }
+ return pattern.charAt(endpoints.start + index);
+}
+
+int32_t ParsedPatternInfo::length(int32_t flags) const {
+ return getLengthFromEndpoints(getEndpoints(flags));
+}
+
+int32_t ParsedPatternInfo::getLengthFromEndpoints(const Endpoints& endpoints) {
+ return endpoints.end - endpoints.start;
+}
+
+UnicodeString ParsedPatternInfo::getString(int32_t flags) const {
+ const Endpoints& endpoints = getEndpoints(flags);
+ if (endpoints.start == endpoints.end) {
+ return UnicodeString();
+ }
+ // Create a new UnicodeString
+ return UnicodeString(pattern, endpoints.start, endpoints.end - endpoints.start);
+}
+
+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;
+ if (isNegative && padding) {
+ return negative.paddingEndpoints;
+ } else if (padding) {
+ return positive.paddingEndpoints;
+ } else if (prefix && isNegative) {
+ return negative.prefixEndpoints;
+ } else if (prefix) {
+ return positive.prefixEndpoints;
+ } else if (isNegative) {
+ return negative.suffixEndpoints;
+ } else {
+ return positive.suffixEndpoints;
+ }
+}
+
+bool ParsedPatternInfo::positiveHasPlusSign() const {
+ return positive.hasPlusSign;
+}
+
+bool ParsedPatternInfo::hasNegativeSubpattern() const {
+ return fHasNegativeSubpattern;
+}
+
+bool ParsedPatternInfo::negativeHasMinusSign() const {
+ return negative.hasMinusSign;
+}
+
+bool ParsedPatternInfo::hasCurrencySign() const {
+ return positive.hasCurrencySign || (fHasNegativeSubpattern && negative.hasCurrencySign);
+}
+
+bool ParsedPatternInfo::containsSymbolType(AffixPatternType type, UErrorCode& status) const {
+ return AffixUtils::containsType(pattern, type, status);
+}
+
+bool ParsedPatternInfo::hasBody() const {
+ return positive.integerTotal > 0;
+}
+
+/////////////////////////////////////////////////////
+/// BEGIN RECURSIVE DESCENT PARSER IMPLEMENTATION ///
+/////////////////////////////////////////////////////
+
+UChar32 ParsedPatternInfo::ParserState::peek() {
+ if (offset == pattern.length()) {
+ return -1;
+ } else {
+ return pattern.char32At(offset);
+ }
+}
+
+UChar32 ParsedPatternInfo::ParserState::next() {
+ int codePoint = peek();
+ offset += U16_LENGTH(codePoint);
+ return codePoint;
+}
+
+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);
+ if (U_FAILURE(status)) { return; }
+ if (state.peek() == u';') {
+ state.next(); // consume the ';'
+ // Don't consume the negative subpattern if it is empty (trailing ';')
+ if (state.peek() != -1) {
+ fHasNegativeSubpattern = true;
+ currentSubpattern = &negative;
+ consumeSubpattern(status);
+ if (U_FAILURE(status)) { return; }
+ }
+ }
+ if (state.peek() != -1) {
+ state.toParseException(u"Found unquoted special character");
+ status = U_UNQUOTED_SPECIAL;
+ }
+}
+
+void ParsedPatternInfo::consumeSubpattern(UErrorCode& status) {
+ // subpattern := literals? number exponent? literals?
+ consumePadding(PadPosition::UNUM_PAD_BEFORE_PREFIX, status);
+ if (U_FAILURE(status)) { return; }
+ consumeAffix(currentSubpattern->prefixEndpoints, status);
+ if (U_FAILURE(status)) { return; }
+ consumePadding(PadPosition::UNUM_PAD_AFTER_PREFIX, status);
+ if (U_FAILURE(status)) { return; }
+ consumeFormat(status);
+ if (U_FAILURE(status)) { return; }
+ consumeExponent(status);
+ if (U_FAILURE(status)) { return; }
+ consumePadding(PadPosition::UNUM_PAD_BEFORE_SUFFIX, status);
+ if (U_FAILURE(status)) { return; }
+ consumeAffix(currentSubpattern->suffixEndpoints, status);
+ if (U_FAILURE(status)) { return; }
+ consumePadding(PadPosition::UNUM_PAD_AFTER_SUFFIX, status);
+ if (U_FAILURE(status)) { return; }
+}
+
+void ParsedPatternInfo::consumePadding(PadPosition paddingLocation, UErrorCode& status) {
+ if (state.peek() != u'*') {
+ return;
+ }
+ 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) {
+ // literals := { literal }
+ endpoints.start = state.offset;
+ while (true) {
+ switch (state.peek()) {
+ case u'#':
+ case u'@':
+ case u';':
+ case u'*':
+ case u'.':
+ case u',':
+ case u'0':
+ case u'1':
+ case u'2':
+ case u'3':
+ case u'4':
+ case u'5':
+ case u'6':
+ case u'7':
+ case u'8':
+ case u'9':
+ case -1:
+ // Characters that cannot appear unquoted in a literal
+ // break outer;
+ goto after_outer;
+
+ case u'%':
+ currentSubpattern->hasPercentSign = true;
+ break;
+
+ case u'‰':
+ currentSubpattern->hasPerMilleSign = true;
+ break;
+
+ case u'¤':
+ currentSubpattern->hasCurrencySign = true;
+ break;
+
+ case u'-':
+ currentSubpattern->hasMinusSign = true;
+ break;
+
+ case u'+':
+ currentSubpattern->hasPlusSign = true;
+ break;
+
+ default:
+ break;
+ }
+ consumeLiteral(status);
+ if (U_FAILURE(status)) { return; }
+ }
+ after_outer:
+ endpoints.end = state.offset;
+}
+
+void ParsedPatternInfo::consumeLiteral(UErrorCode& status) {
+ if (state.peek() == -1) {
+ state.toParseException(u"Expected unquoted literal but found EOL");
+ status = U_PATTERN_SYNTAX_ERROR;
+ return;
+ } else if (state.peek() == u'\'') {
+ state.next(); // consume the starting quote
+ while (state.peek() != u'\'') {
+ if (state.peek() == -1) {
+ state.toParseException(u"Expected quoted literal but found EOL");
+ status = U_PATTERN_SYNTAX_ERROR;
+ return;
+ } else {
+ state.next(); // consume a quoted character
+ }
+ }
+ state.next(); // consume the ending quote
+ } else {
+ // consume a non-quoted literal character
+ state.next();
+ }
+}
+
+void ParsedPatternInfo::consumeFormat(UErrorCode& status) {
+ consumeIntegerFormat(status);
+ if (U_FAILURE(status)) { return; }
+ if (state.peek() == u'.') {
+ state.next(); // consume the decimal point
+ currentSubpattern->hasDecimal = true;
+ currentSubpattern->widthExceptAffixes += 1;
+ consumeFractionFormat(status);
+ if (U_FAILURE(status)) { return; }
+ }
+}
+
+void ParsedPatternInfo::consumeIntegerFormat(UErrorCode& status) {
+ // Convenience reference:
+ ParsedSubpatternInfo& result = *currentSubpattern;
+
+ while (true) {
+ switch (state.peek()) {
+ case u',':
+ result.widthExceptAffixes += 1;
+ result.groupingSizes <<= 16;
+ break;
+
+ case u'#':
+ if (result.integerNumerals > 0) {
+ state.toParseException(u"# cannot follow 0 before decimal point");
+ status = U_UNEXPECTED_TOKEN;
+ return;
+ }
+ result.widthExceptAffixes += 1;
+ result.groupingSizes += 1;
+ if (result.integerAtSigns > 0) {
+ result.integerTrailingHashSigns += 1;
+ } else {
+ result.integerLeadingHashSigns += 1;
+ }
+ result.integerTotal += 1;
+ break;
+
+ case u'@':
+ if (result.integerNumerals > 0) {
+ state.toParseException(u"Cannot mix 0 and @");
+ status = U_UNEXPECTED_TOKEN;
+ return;
+ }
+ if (result.integerTrailingHashSigns > 0) {
+ state.toParseException(u"Cannot nest # inside of a run of @");
+ status = U_UNEXPECTED_TOKEN;
+ return;
+ }
+ result.widthExceptAffixes += 1;
+ result.groupingSizes += 1;
+ result.integerAtSigns += 1;
+ result.integerTotal += 1;
+ break;
+
+ case u'0':
+ case u'1':
+ case u'2':
+ case u'3':
+ case u'4':
+ case u'5':
+ case u'6':
+ case u'7':
+ case u'8':
+ case u'9':
+ if (result.integerAtSigns > 0) {
+ state.toParseException(u"Cannot mix @ and 0");
+ status = U_UNEXPECTED_TOKEN;
+ return;
+ }
+ result.widthExceptAffixes += 1;
+ result.groupingSizes += 1;
+ result.integerNumerals += 1;
+ result.integerTotal += 1;
+ if (!result.rounding.isZeroish() || state.peek() != u'0') {
+ result.rounding.appendDigit(static_cast<int8_t>(state.peek() - u'0'), 0, true);
+ }
+ break;
+
+ default:
+ goto after_outer;
+ }
+ state.next(); // consume the symbol
+ }
+
+ after_outer:
+ // Disallow patterns with a trailing ',' or with two ',' next to each other
+ auto grouping1 = static_cast<int16_t> (result.groupingSizes & 0xffff);
+ auto grouping2 = static_cast<int16_t> ((result.groupingSizes >> 16) & 0xffff);
+ auto grouping3 = static_cast<int16_t> ((result.groupingSizes >> 32) & 0xffff);
+ if (grouping1 == 0 && grouping2 != -1) {
+ state.toParseException(u"Trailing grouping separator is invalid");
+ status = U_UNEXPECTED_TOKEN;
+ return;
+ }
+ if (grouping2 == 0 && grouping3 != -1) {
+ state.toParseException(u"Grouping width of zero is invalid");
+ status = U_PATTERN_SYNTAX_ERROR;
+ return;
+ }
+}
+
+void ParsedPatternInfo::consumeFractionFormat(UErrorCode& status) {
+ // Convenience reference:
+ ParsedSubpatternInfo& result = *currentSubpattern;
+
+ int32_t zeroCounter = 0;
+ while (true) {
+ switch (state.peek()) {
+ case u'#':
+ result.widthExceptAffixes += 1;
+ result.fractionHashSigns += 1;
+ result.fractionTotal += 1;
+ zeroCounter++;
+ break;
+
+ case u'0':
+ case u'1':
+ case u'2':
+ case u'3':
+ case u'4':
+ case u'5':
+ case u'6':
+ case u'7':
+ case u'8':
+ case u'9':
+ if (result.fractionHashSigns > 0) {
+ state.toParseException(u"0 cannot follow # after decimal point");
+ status = U_UNEXPECTED_TOKEN;
+ return;
+ }
+ result.widthExceptAffixes += 1;
+ result.fractionNumerals += 1;
+ result.fractionTotal += 1;
+ if (state.peek() == u'0') {
+ zeroCounter++;
+ } else {
+ result.rounding
+ .appendDigit(static_cast<int8_t>(state.peek() - u'0'), zeroCounter, false);
+ zeroCounter = 0;
+ }
+ break;
+
+ default:
+ return;
+ }
+ state.next(); // consume the symbol
+ }
+}
+
+void ParsedPatternInfo::consumeExponent(UErrorCode& status) {
+ // Convenience reference:
+ ParsedSubpatternInfo& result = *currentSubpattern;
+
+ if (state.peek() != u'E') {
+ return;
+ }
+ if ((result.groupingSizes & 0xffff0000L) != 0xffff0000L) {
+ state.toParseException(u"Cannot have grouping separator in scientific notation");
+ status = U_MALFORMED_EXPONENTIAL_PATTERN;
+ return;
+ }
+ state.next(); // consume the E
+ result.widthExceptAffixes++;
+ if (state.peek() == u'+') {
+ state.next(); // consume the +
+ result.exponentHasPlusSign = true;
+ result.widthExceptAffixes++;
+ }
+ while (state.peek() == u'0') {
+ state.next(); // consume the 0
+ result.exponentZeros += 1;
+ result.widthExceptAffixes++;
+ }
+}
+
+///////////////////////////////////////////////////
+/// END RECURSIVE DESCENT PARSER IMPLEMENTATION ///
+///////////////////////////////////////////////////
+
+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?
+ properties.clear();
+ return;
+ }
+
+ ParsedPatternInfo patternInfo;
+ parseToPatternInfo(pattern, patternInfo, status);
+ if (U_FAILURE(status)) { return; }
+ patternInfoToProperties(properties, patternInfo, ignoreRounding, 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;
+
+ bool ignoreRounding;
+ if (_ignoreRounding == IGNORE_ROUNDING_NEVER) {
+ ignoreRounding = false;
+ } else if (_ignoreRounding == IGNORE_ROUNDING_IF_CURRENCY) {
+ ignoreRounding = positive.hasCurrencySign;
+ } else {
+ U_ASSERT(_ignoreRounding == IGNORE_ROUNDING_ALWAYS);
+ ignoreRounding = true;
+ }
+
+ // Grouping settings
+ auto grouping1 = static_cast<int16_t> (positive.groupingSizes & 0xffff);
+ auto grouping2 = static_cast<int16_t> ((positive.groupingSizes >> 16) & 0xffff);
+ auto grouping3 = static_cast<int16_t> ((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;
+ } else {
+ properties.secondaryGroupingSize = -1;
+ }
+
+ // For backwards compatibility, require that the pattern emit at least one min digit.
+ int minInt, minFrac;
+ if (positive.integerTotal == 0 && positive.fractionTotal > 0) {
+ // patterns like ".##"
+ minInt = 0;
+ minFrac = uprv_max(1, positive.fractionNumerals);
+ } else if (positive.integerNumerals == 0 && positive.fractionNumerals == 0) {
+ // patterns like "#.##"
+ minInt = 1;
+ minFrac = 0;
+ } else {
+ minInt = positive.integerNumerals;
+ minFrac = positive.fractionNumerals;
+ }
+
+ // Rounding settings
+ // Don't set basic rounding when there is a currency sign; defer to CurrencyUsage
+ if (positive.integerAtSigns > 0) {
+ properties.minimumFractionDigits = -1;
+ properties.maximumFractionDigits = -1;
+ properties.roundingIncrement = 0.0;
+ properties.minimumSignificantDigits = positive.integerAtSigns;
+ properties.maximumSignificantDigits = positive.integerAtSigns + positive.integerTrailingHashSigns;
+ } else if (!positive.rounding.isZeroish()) {
+ if (!ignoreRounding) {
+ properties.minimumFractionDigits = minFrac;
+ properties.maximumFractionDigits = positive.fractionTotal;
+ properties.roundingIncrement = positive.rounding.toDouble();
+ } else {
+ properties.minimumFractionDigits = -1;
+ properties.maximumFractionDigits = -1;
+ properties.roundingIncrement = 0.0;
+ }
+ properties.minimumSignificantDigits = -1;
+ properties.maximumSignificantDigits = -1;
+ } else {
+ if (!ignoreRounding) {
+ properties.minimumFractionDigits = minFrac;
+ properties.maximumFractionDigits = positive.fractionTotal;
+ properties.roundingIncrement = 0.0;
+ } else {
+ properties.minimumFractionDigits = -1;
+ properties.maximumFractionDigits = -1;
+ properties.roundingIncrement = 0.0;
+ }
+ properties.minimumSignificantDigits = -1;
+ properties.maximumSignificantDigits = -1;
+ }
+
+ // If the pattern ends with a '.' then force the decimal point.
+ if (positive.hasDecimal && positive.fractionTotal == 0) {
+ properties.decimalSeparatorAlwaysShown = true;
+ } else {
+ properties.decimalSeparatorAlwaysShown = false;
+ }
+
+ // Scientific notation settings
+ if (positive.exponentZeros > 0) {
+ properties.exponentSignAlwaysShown = positive.exponentHasPlusSign;
+ properties.minimumExponentDigits = positive.exponentZeros;
+ if (positive.integerAtSigns == 0) {
+ // patterns without '@' can define max integer digits, used for engineering notation
+ properties.minimumIntegerDigits = positive.integerNumerals;
+ properties.maximumIntegerDigits = positive.integerTotal;
+ } else {
+ // patterns with '@' cannot define max integer digits
+ properties.minimumIntegerDigits = 1;
+ properties.maximumIntegerDigits = -1;
+ }
+ } else {
+ properties.exponentSignAlwaysShown = false;
+ properties.minimumExponentDigits = -1;
+ properties.minimumIntegerDigits = minInt;
+ properties.maximumIntegerDigits = -1;
+ }
+
+ // Compute the affix patterns (required for both padding and affixes)
+ UnicodeString posPrefix = patternInfo.getString(AffixPatternProvider::AFFIX_PREFIX);
+ UnicodeString posSuffix = patternInfo.getString(0);
+
+ // Padding settings
+ if (positive.hasPadding) {
+ // The width of the positive prefix and suffix templates are included in the padding
+ 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) {
+ properties.padString = rawPaddingString;
+ } else if (rawPaddingString.length() == 2) {
+ if (rawPaddingString.charAt(0) == u'\'') {
+ properties.padString.setTo(u"'", -1);
+ } else {
+ properties.padString = rawPaddingString;
+ }
+ } else {
+ properties.padString = UnicodeString(rawPaddingString, 1, rawPaddingString.length() - 2);
+ }
+ properties.padPosition = positive.paddingLocation;
+ } else {
+ properties.formatWidth = -1;
+ properties.padString.setToBogus();
+ properties.padPosition.nullify();
+ }
+
+ // Set the affixes
+ // Always call the setter, even if the prefixes are empty, especially in the case of the
+ // negative prefix pattern, to prevent default values from overriding the pattern.
+ properties.positivePrefixPattern = posPrefix;
+ properties.positiveSuffixPattern = posSuffix;
+ if (patternInfo.fHasNegativeSubpattern) {
+ properties.negativePrefixPattern = patternInfo.getString(
+ AffixPatternProvider::AFFIX_NEGATIVE_SUBPATTERN | AffixPatternProvider::AFFIX_PREFIX);
+ properties.negativeSuffixPattern = patternInfo.getString(
+ AffixPatternProvider::AFFIX_NEGATIVE_SUBPATTERN);
+ } else {
+ properties.negativePrefixPattern.setToBogus();
+ properties.negativeSuffixPattern.setToBogus();
+ }
+
+ // Set the magnitude multiplier
+ if (positive.hasPercentSign) {
+ properties.magnitudeMultiplier = 2;
+ } else if (positive.hasPerMilleSign) {
+ properties.magnitudeMultiplier = 3;
+ } else {
+ properties.magnitudeMultiplier = 0;
+ }
+}
+
+///////////////////////////////////////////////////////////////////
+/// End PatternStringParser.java; begin PatternStringUtils.java ///
+///////////////////////////////////////////////////////////////////
+
+// Determine whether a given roundingIncrement should be ignored for formatting
+// based on the current maxFrac value (maximum fraction digits). For example a
+// roundingIncrement of 0.01 should be ignored if maxFrac is 1, but not if maxFrac
+// is 2 or more. Note that roundingIncrements are rounded in significance, so
+// a roundingIncrement of 0.006 is treated like 0.01 for this determination, i.e.
+// it should not be ignored if maxFrac is 2 or more (but a roundingIncrement of
+// 0.005 is treated like 0.001 for significance). This is the reason for the
+// initial doubling below.
+// roundIncr must be non-zero.
+bool PatternStringUtils::ignoreRoundingIncrement(double roundIncr, int32_t maxFrac) {
+ if (maxFrac < 0) {
+ return false;
+ }
+ int32_t frac = 0;
+ roundIncr *= 2.0;
+ for (frac = 0; frac <= maxFrac && roundIncr <= 1.0; frac++, roundIncr *= 10.0);
+ return (frac > maxFrac);
+}
+
+UnicodeString PatternStringUtils::propertiesToPatternString(const DecimalFormatProperties& properties,
+ UErrorCode& status) {
+ UnicodeString sb;
+
+ // Convenience references
+ // The uprv_min() calls prevent DoS
+ int32_t dosMax = 100;
+ int32_t grouping1 = uprv_max(0, uprv_min(properties.groupingSize, dosMax));
+ int32_t grouping2 = uprv_max(0, uprv_min(properties.secondaryGroupingSize, dosMax));
+ bool useGrouping = properties.groupingUsed;
+ int32_t paddingWidth = uprv_min(properties.formatWidth, dosMax);
+ NullableValue<PadPosition> paddingLocation = properties.padPosition;
+ UnicodeString paddingString = properties.padString;
+ int32_t minInt = uprv_max(0, uprv_min(properties.minimumIntegerDigits, dosMax));
+ int32_t maxInt = uprv_min(properties.maximumIntegerDigits, dosMax);
+ int32_t minFrac = uprv_max(0, uprv_min(properties.minimumFractionDigits, dosMax));
+ int32_t maxFrac = uprv_min(properties.maximumFractionDigits, dosMax);
+ int32_t minSig = uprv_min(properties.minimumSignificantDigits, dosMax);
+ int32_t maxSig = uprv_min(properties.maximumSignificantDigits, dosMax);
+ bool alwaysShowDecimal = properties.decimalSeparatorAlwaysShown;
+ int32_t exponentDigits = uprv_min(properties.minimumExponentDigits, dosMax);
+ bool exponentShowPlusSign = properties.exponentSignAlwaysShown;
+
+ AutoAffixPatternProvider affixProvider(properties, status);
+
+ // Prefixes
+ sb.append(affixProvider.get().getString(AffixPatternProvider::AFFIX_POS_PREFIX));
+ int32_t afterPrefixPos = sb.length();
+
+ // Figure out the grouping sizes.
+ if (!useGrouping) {
+ grouping1 = 0;
+ grouping2 = 0;
+ } else if (grouping1 == grouping2) {
+ grouping1 = 0;
+ }
+ int32_t groupingLength = grouping1 + grouping2 + 1;
+
+ // Figure out the digits we need to put in the pattern.
+ double roundingInterval = properties.roundingIncrement;
+ UnicodeString digitsString;
+ int32_t digitsStringScale = 0;
+ if (maxSig != uprv_min(dosMax, -1)) {
+ // Significant Digits.
+ while (digitsString.length() < minSig) {
+ digitsString.append(u'@');
+ }
+ while (digitsString.length() < maxSig) {
+ digitsString.append(u'#');
+ }
+ } else if (roundingInterval != 0.0 && !ignoreRoundingIncrement(roundingInterval,maxFrac)) {
+ // Rounding Interval.
+ digitsStringScale = -roundingutils::doubleFractionLength(roundingInterval, nullptr);
+ // TODO: Check for DoS here?
+ DecimalQuantity incrementQuantity;
+ incrementQuantity.setToDouble(roundingInterval);
+ incrementQuantity.adjustMagnitude(-digitsStringScale);
+ incrementQuantity.roundToMagnitude(0, kDefaultMode, status);
+ UnicodeString str = incrementQuantity.toPlainString();
+ if (str.charAt(0) == u'-') {
+ // TODO: Unsupported operation exception or fail silently?
+ digitsString.append(str, 1, str.length() - 1);
+ } else {
+ digitsString.append(str);
+ }
+ }
+ while (digitsString.length() + digitsStringScale < minInt) {
+ digitsString.insert(0, u'0');
+ }
+ while (-digitsStringScale < minFrac) {
+ digitsString.append(u'0');
+ digitsStringScale--;
+ }
+
+ // Write the digits to the string builder
+ int32_t m0 = uprv_max(groupingLength, digitsString.length() + digitsStringScale);
+ m0 = (maxInt != dosMax) ? uprv_max(maxInt, m0) - 1 : m0 - 1;
+ int32_t mN = (maxFrac != dosMax) ? uprv_min(-maxFrac, digitsStringScale) : digitsStringScale;
+ for (int32_t magnitude = m0; magnitude >= mN; magnitude--) {
+ int32_t di = digitsString.length() + digitsStringScale - magnitude - 1;
+ if (di < 0 || di >= digitsString.length()) {
+ sb.append(u'#');
+ } else {
+ sb.append(digitsString.charAt(di));
+ }
+ // Decimal separator
+ if (magnitude == 0 && (alwaysShowDecimal || mN < 0)) {
+ sb.append(u'.');
+ }
+ if (!useGrouping) {
+ continue;
+ }
+ // Least-significant grouping separator
+ if (magnitude > 0 && magnitude == grouping1) {
+ sb.append(u',');
+ }
+ // All other grouping separators
+ if (magnitude > grouping1 && grouping2 > 0 && (magnitude - grouping1) % grouping2 == 0) {
+ sb.append(u',');
+ }
+ }
+
+ // Exponential notation
+ if (exponentDigits != uprv_min(dosMax, -1)) {
+ sb.append(u'E');
+ if (exponentShowPlusSign) {
+ sb.append(u'+');
+ }
+ for (int32_t i = 0; i < exponentDigits; i++) {
+ sb.append(u'0');
+ }
+ }
+
+ // Suffixes
+ int32_t beforeSuffixPos = sb.length();
+ sb.append(affixProvider.get().getString(AffixPatternProvider::AFFIX_POS_SUFFIX));
+
+ // Resolve Padding
+ if (paddingWidth > 0 && !paddingLocation.isNull()) {
+ while (paddingWidth - sb.length() > 0) {
+ sb.insert(afterPrefixPos, u'#');
+ beforeSuffixPos++;
+ }
+ int32_t addedLength;
+ switch (paddingLocation.get(status)) {
+ case PadPosition::UNUM_PAD_BEFORE_PREFIX:
+ addedLength = escapePaddingString(paddingString, sb, 0, status);
+ sb.insert(0, u'*');
+ afterPrefixPos += addedLength + 1;
+ beforeSuffixPos += addedLength + 1;
+ break;
+ case PadPosition::UNUM_PAD_AFTER_PREFIX:
+ addedLength = escapePaddingString(paddingString, sb, afterPrefixPos, status);
+ sb.insert(afterPrefixPos, u'*');
+ afterPrefixPos += addedLength + 1;
+ beforeSuffixPos += addedLength + 1;
+ break;
+ case PadPosition::UNUM_PAD_BEFORE_SUFFIX:
+ escapePaddingString(paddingString, sb, beforeSuffixPos, status);
+ sb.insert(beforeSuffixPos, u'*');
+ break;
+ case PadPosition::UNUM_PAD_AFTER_SUFFIX:
+ sb.append(u'*');
+ escapePaddingString(paddingString, sb, sb.length(), status);
+ break;
+ }
+ if (U_FAILURE(status)) { return sb; }
+ }
+
+ // Negative affixes
+ // Ignore if the negative prefix pattern is "-" and the negative suffix is empty
+ if (affixProvider.get().hasNegativeSubpattern()) {
+ sb.append(u';');
+ sb.append(affixProvider.get().getString(AffixPatternProvider::AFFIX_NEG_PREFIX));
+ // Copy the positive digit format into the negative.
+ // This is optional; the pattern is the same as if '#' were appended here instead.
+ // 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);
+ sb.append(affixProvider.get().getString(AffixPatternProvider::AFFIX_NEG_SUFFIX));
+ }
+
+ return sb;
+}
+
+int PatternStringUtils::escapePaddingString(UnicodeString input, UnicodeString& output, int startIndex,
+ UErrorCode& status) {
+ (void) status;
+ if (input.length() == 0) {
+ input.setTo(kFallbackPaddingString, -1);
+ }
+ int startLength = output.length();
+ if (input.length() == 1) {
+ if (input.compare(u"'", -1) == 0) {
+ output.insert(startIndex, u"''", -1);
+ } else {
+ output.insert(startIndex, input);
+ }
+ } else {
+ output.insert(startIndex, u'\'');
+ int offset = 1;
+ for (int i = 0; i < input.length(); i++) {
+ // it's okay to deal in chars here because the quote mark is the only interesting thing.
+ char16_t ch = input.charAt(i);
+ if (ch == u'\'') {
+ output.insert(startIndex + offset, u"''", -1);
+ offset += 2;
+ } else {
+ output.insert(startIndex + offset, ch);
+ offset += 1;
+ }
+ }
+ output.insert(startIndex + offset, u'\'');
+ }
+ 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,
+ PatternSignType patternSignType,
+ StandardPlural::Form plural,
+ bool perMilleReplacesPercent, UnicodeString& output) {
+
+ // Should the output render '+' where '-' would normally appear in the pattern?
+ bool plusReplacesMinusSign = (patternSignType == PATTERN_SIGN_TYPE_POS_SIGN)
+ && !patternInfo.positiveHasPlusSign();
+
+ // Should we use the affix from the negative subpattern?
+ // (If not, we will use the positive subpattern.)
+ bool useNegativeAffixPattern = patternInfo.hasNegativeSubpattern()
+ && (patternSignType == PATTERN_SIGN_TYPE_NEG
+ || (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 (patternSignType == PATTERN_SIGN_TYPE_NEG) {
+ prependSign = true;
+ } 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);
+ }
+}
+
+PatternSignType PatternStringUtils::resolveSignDisplay(UNumberSignDisplay signDisplay, Signum signum) {
+ switch (signDisplay) {
+ case UNUM_SIGN_AUTO:
+ case UNUM_SIGN_ACCOUNTING:
+ switch (signum) {
+ case SIGNUM_NEG:
+ case SIGNUM_NEG_ZERO:
+ return PATTERN_SIGN_TYPE_NEG;
+ case SIGNUM_POS_ZERO:
+ case SIGNUM_POS:
+ return PATTERN_SIGN_TYPE_POS;
+ default:
+ break;
+ }
+ break;
+
+ case UNUM_SIGN_ALWAYS:
+ case UNUM_SIGN_ACCOUNTING_ALWAYS:
+ switch (signum) {
+ case SIGNUM_NEG:
+ case SIGNUM_NEG_ZERO:
+ return PATTERN_SIGN_TYPE_NEG;
+ case SIGNUM_POS_ZERO:
+ case SIGNUM_POS:
+ return PATTERN_SIGN_TYPE_POS_SIGN;
+ default:
+ break;
+ }
+ break;
+
+ case UNUM_SIGN_EXCEPT_ZERO:
+ case UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO:
+ switch (signum) {
+ case SIGNUM_NEG:
+ return PATTERN_SIGN_TYPE_NEG;
+ case SIGNUM_NEG_ZERO:
+ case SIGNUM_POS_ZERO:
+ return PATTERN_SIGN_TYPE_POS;
+ case SIGNUM_POS:
+ return PATTERN_SIGN_TYPE_POS_SIGN;
+ default:
+ break;
+ }
+ break;
+
+ case UNUM_SIGN_NEVER:
+ return PATTERN_SIGN_TYPE_POS;
+
+ default:
+ break;
+ }
+
+ UPRV_UNREACHABLE;
+ return PATTERN_SIGN_TYPE_POS;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_patternstring.h b/contrib/libs/icu/i18n/number_patternstring.h
index 54f37fd7e2..b25f1afa43 100644
--- a/contrib/libs/icu/i18n/number_patternstring.h
+++ b/contrib/libs/icu/i18n/number_patternstring.h
@@ -1,329 +1,329 @@
-// © 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_PATTERNSTRING_H__
-#define __NUMBER_PATTERNSTRING_H__
-
-
-#include <cstdint>
-#include "unicode/unum.h"
-#include "unicode/unistr.h"
-#include "number_types.h"
-#include "number_decimalquantity.h"
-#include "number_decimfmtprops.h"
-#include "number_affixutils.h"
-
-U_NAMESPACE_BEGIN namespace number {
-namespace impl {
-
-// Forward declaration
-class PatternParser;
-
-// Note: the order of fields in this enum matters for parsing.
-enum PatternSignType {
- /** Render using normal positive subpattern rules */
- PATTERN_SIGN_TYPE_POS,
- /** Render using rules to force the display of a plus sign */
- PATTERN_SIGN_TYPE_POS_SIGN,
- /** Render using negative subpattern rules */
- PATTERN_SIGN_TYPE_NEG,
- /** Count for looping over the possibilities */
- PATTERN_SIGN_TYPE_COUNT
-};
-
-// Exported as U_I18N_API because it is a public member field of exported ParsedSubpatternInfo
-struct U_I18N_API Endpoints {
- int32_t start = 0;
- int32_t end = 0;
-};
-
-// Exported as U_I18N_API because it is a public member field of exported ParsedPatternInfo
-struct U_I18N_API ParsedSubpatternInfo {
- uint64_t groupingSizes = 0x0000ffffffff0000L;
- int32_t integerLeadingHashSigns = 0;
- int32_t integerTrailingHashSigns = 0;
- int32_t integerNumerals = 0;
- int32_t integerAtSigns = 0;
- int32_t integerTotal = 0; // for convenience
- int32_t fractionNumerals = 0;
- int32_t fractionHashSigns = 0;
- int32_t fractionTotal = 0; // for convenience
- bool hasDecimal = false;
- int32_t widthExceptAffixes = 0;
- // 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;
- bool hasPercentSign = false;
- bool hasPerMilleSign = false;
- bool hasCurrencySign = false;
- bool hasMinusSign = false;
- bool hasPlusSign = false;
-
- Endpoints prefixEndpoints;
- Endpoints suffixEndpoints;
- Endpoints paddingEndpoints;
-};
-
-// Exported as U_I18N_API because it is needed for the unit test PatternStringTest
-struct U_I18N_API ParsedPatternInfo : public AffixPatternProvider, public UMemory {
- UnicodeString pattern;
- ParsedSubpatternInfo positive;
- ParsedSubpatternInfo negative;
-
- ParsedPatternInfo()
- : state(this->pattern), currentSubpattern(nullptr) {}
-
- ~ParsedPatternInfo() U_OVERRIDE = default;
-
- // 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 U_OVERRIDE;
-
- bool positiveHasPlusSign() const U_OVERRIDE;
-
- bool hasNegativeSubpattern() const U_OVERRIDE;
-
- bool negativeHasMinusSign() const U_OVERRIDE;
-
- bool hasCurrencySign() 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
- int32_t offset = 0;
-
- 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();
-
- UChar32 next();
-
- // 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;
-
- // 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;
-
- // 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;
-
- /** Run the recursive descent parser. */
- void consumePattern(const UnicodeString& patternString, UErrorCode& status);
-
- void consumeSubpattern(UErrorCode& status);
-
- void consumePadding(PadPosition paddingLocation, UErrorCode& status);
-
- void consumeAffix(Endpoints& endpoints, UErrorCode& status);
-
- void consumeLiteral(UErrorCode& status);
-
- void consumeFormat(UErrorCode& status);
-
- void consumeIntegerFormat(UErrorCode& status);
-
- void consumeFractionFormat(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:
- /**
- * Runs the recursive descent parser on the given pattern string, returning a data structure with raw information
- * about the pattern string.
- *
- * <p>
- * To obtain a more useful form of the data, consider using {@link #parseToProperties} instead.
- *
- * TODO: Change argument type to const char16_t* instead of UnicodeString?
- *
- * @param patternString
- * 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);
-
- /**
- * Parses a pattern string into a new property bag.
- *
- * @param pattern
- * The pattern string, like "#,##0.00"
- * @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.
- * @return A property bag object.
- * @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, UErrorCode& status);
-
- /**
- * Parses a pattern string into an existing property bag. All properties that can be encoded into a pattern string
- * will be overwritten with either their default value or with the value coming from the pattern string. Properties
- * that cannot be encoded into a pattern string, such as rounding mode, are not modified.
- *
- * @param pattern
- * The pattern string, like "#,##0.00"
- * @param properties
- * The property bag object to overwrite.
- * @param ignoreRounding
- * See {@link #parseToProperties(String pattern, int ignoreRounding)}.
- * @throws IllegalArgumentException
- * If there was a syntax error in the pattern string.
- */
- 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);
-
- /** Finalizes the temporary data stored in the ParsedPatternInfo to the Properties. */
- static void patternInfoToProperties(DecimalFormatProperties& properties,
- ParsedPatternInfo& patternInfo, IgnoreRounding _ignoreRounding,
- UErrorCode& status);
-};
-
-class U_I18N_API PatternStringUtils {
- public:
- /**
- * Determine whether a given roundingIncrement should be ignored for formatting
- * based on the current maxFrac value (maximum fraction digits). For example a
- * roundingIncrement of 0.01 should be ignored if maxFrac is 1, but not if maxFrac
- * is 2 or more. Note that roundingIncrements are rounded up in significance, so
- * a roundingIncrement of 0.006 is treated like 0.01 for this determination, i.e.
- * it should not be ignored if maxFrac is 2 or more (but a roundingIncrement of
- * 0.005 is treated like 0.001 for significance).
- *
- * This test is needed for both NumberPropertyMapper::oldToNew and
- * PatternStringUtils::propertiesToPatternString. In Java it cannot be
- * exported by NumberPropertyMapper (package provate) so it is in
- * PatternStringUtils, do the same in C.
- *
- * @param roundIncr
- * The roundingIncrement to be checked. Must be non-zero.
- * @param maxFrac
- * The current maximum fraction digits value.
- * @return true if roundIncr should be ignored for formatting.
- */
- static bool ignoreRoundingIncrement(double roundIncr, int32_t maxFrac);
-
- /**
- * Creates a pattern string from a property bag.
- *
- * <p>
- * Since pattern strings support only a subset of the functionality available in a property bag, a new property bag
- * created from the string returned by this function may not be the same as the original property bag.
- *
- * @param properties
- * The property bag to serialize.
- * @return A pattern string approximately serializing the property bag.
- */
- static UnicodeString propertiesToPatternString(const DecimalFormatProperties& properties,
- UErrorCode& status);
-
-
- /**
- * Converts a pattern between standard notation and localized notation. Localized notation means that instead of
- * using generic placeholders in the pattern, you use the corresponding locale-specific characters instead. For
- * example, in locale <em>fr-FR</em>, the period in the pattern "0.000" means "decimal" in standard notation (as it
- * does in every other locale), but it means "grouping" in localized notation.
- *
- * <p>
- * A greedy string-substitution strategy is used to substitute locale symbols. If two symbols are ambiguous or have
- * the same prefix, the result is not well-defined.
- *
- * <p>
- * Locale symbols are not allowed to contain the ASCII quote character.
- *
- * <p>
- * This method is provided for backwards compatibility and should not be used in any new code.
- *
- * TODO(C++): This method is not yet implemented.
- *
- * @param input
- * The pattern to convert.
- * @param symbols
- * The symbols corresponding to the localized pattern.
- * @param toLocalized
- * true to convert from standard to localized notation; false to convert from localized to standard
- * notation.
- * @return The pattern expressed in the other notation.
- */
- 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,
- PatternSignType patternSignType,
- StandardPlural::Form plural, bool perMilleReplacesPercent,
- UnicodeString& output);
-
- static PatternSignType resolveSignDisplay(UNumberSignDisplay signDisplay, Signum signum);
-
- private:
- /** @return The number of chars inserted. */
- static int escapePaddingString(UnicodeString input, UnicodeString& output, int startIndex,
- UErrorCode& status);
-};
-
-} // namespace impl
-} // namespace number
-U_NAMESPACE_END
-
-
-#endif //__NUMBER_PATTERNSTRING_H__
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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_PATTERNSTRING_H__
+#define __NUMBER_PATTERNSTRING_H__
+
+
+#include <cstdint>
+#include "unicode/unum.h"
+#include "unicode/unistr.h"
+#include "number_types.h"
+#include "number_decimalquantity.h"
+#include "number_decimfmtprops.h"
+#include "number_affixutils.h"
+
+U_NAMESPACE_BEGIN namespace number {
+namespace impl {
+
+// Forward declaration
+class PatternParser;
+
+// Note: the order of fields in this enum matters for parsing.
+enum PatternSignType {
+ /** Render using normal positive subpattern rules */
+ PATTERN_SIGN_TYPE_POS,
+ /** Render using rules to force the display of a plus sign */
+ PATTERN_SIGN_TYPE_POS_SIGN,
+ /** Render using negative subpattern rules */
+ PATTERN_SIGN_TYPE_NEG,
+ /** Count for looping over the possibilities */
+ PATTERN_SIGN_TYPE_COUNT
+};
+
+// Exported as U_I18N_API because it is a public member field of exported ParsedSubpatternInfo
+struct U_I18N_API Endpoints {
+ int32_t start = 0;
+ int32_t end = 0;
+};
+
+// Exported as U_I18N_API because it is a public member field of exported ParsedPatternInfo
+struct U_I18N_API ParsedSubpatternInfo {
+ uint64_t groupingSizes = 0x0000ffffffff0000L;
+ int32_t integerLeadingHashSigns = 0;
+ int32_t integerTrailingHashSigns = 0;
+ int32_t integerNumerals = 0;
+ int32_t integerAtSigns = 0;
+ int32_t integerTotal = 0; // for convenience
+ int32_t fractionNumerals = 0;
+ int32_t fractionHashSigns = 0;
+ int32_t fractionTotal = 0; // for convenience
+ bool hasDecimal = false;
+ int32_t widthExceptAffixes = 0;
+ // 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;
+ bool hasPercentSign = false;
+ bool hasPerMilleSign = false;
+ bool hasCurrencySign = false;
+ bool hasMinusSign = false;
+ bool hasPlusSign = false;
+
+ Endpoints prefixEndpoints;
+ Endpoints suffixEndpoints;
+ Endpoints paddingEndpoints;
+};
+
+// Exported as U_I18N_API because it is needed for the unit test PatternStringTest
+struct U_I18N_API ParsedPatternInfo : public AffixPatternProvider, public UMemory {
+ UnicodeString pattern;
+ ParsedSubpatternInfo positive;
+ ParsedSubpatternInfo negative;
+
+ ParsedPatternInfo()
+ : state(this->pattern), currentSubpattern(nullptr) {}
+
+ ~ParsedPatternInfo() U_OVERRIDE = default;
+
+ // 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 U_OVERRIDE;
+
+ bool positiveHasPlusSign() const U_OVERRIDE;
+
+ bool hasNegativeSubpattern() const U_OVERRIDE;
+
+ bool negativeHasMinusSign() const U_OVERRIDE;
+
+ bool hasCurrencySign() 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
+ int32_t offset = 0;
+
+ 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();
+
+ UChar32 next();
+
+ // 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;
+
+ // 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;
+
+ // 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;
+
+ /** Run the recursive descent parser. */
+ void consumePattern(const UnicodeString& patternString, UErrorCode& status);
+
+ void consumeSubpattern(UErrorCode& status);
+
+ void consumePadding(PadPosition paddingLocation, UErrorCode& status);
+
+ void consumeAffix(Endpoints& endpoints, UErrorCode& status);
+
+ void consumeLiteral(UErrorCode& status);
+
+ void consumeFormat(UErrorCode& status);
+
+ void consumeIntegerFormat(UErrorCode& status);
+
+ void consumeFractionFormat(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:
+ /**
+ * Runs the recursive descent parser on the given pattern string, returning a data structure with raw information
+ * about the pattern string.
+ *
+ * <p>
+ * To obtain a more useful form of the data, consider using {@link #parseToProperties} instead.
+ *
+ * TODO: Change argument type to const char16_t* instead of UnicodeString?
+ *
+ * @param patternString
+ * 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);
+
+ /**
+ * Parses a pattern string into a new property bag.
+ *
+ * @param pattern
+ * The pattern string, like "#,##0.00"
+ * @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.
+ * @return A property bag object.
+ * @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, UErrorCode& status);
+
+ /**
+ * Parses a pattern string into an existing property bag. All properties that can be encoded into a pattern string
+ * will be overwritten with either their default value or with the value coming from the pattern string. Properties
+ * that cannot be encoded into a pattern string, such as rounding mode, are not modified.
+ *
+ * @param pattern
+ * The pattern string, like "#,##0.00"
+ * @param properties
+ * The property bag object to overwrite.
+ * @param ignoreRounding
+ * See {@link #parseToProperties(String pattern, int ignoreRounding)}.
+ * @throws IllegalArgumentException
+ * If there was a syntax error in the pattern string.
+ */
+ 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);
+
+ /** Finalizes the temporary data stored in the ParsedPatternInfo to the Properties. */
+ static void patternInfoToProperties(DecimalFormatProperties& properties,
+ ParsedPatternInfo& patternInfo, IgnoreRounding _ignoreRounding,
+ UErrorCode& status);
+};
+
+class U_I18N_API PatternStringUtils {
+ public:
+ /**
+ * Determine whether a given roundingIncrement should be ignored for formatting
+ * based on the current maxFrac value (maximum fraction digits). For example a
+ * roundingIncrement of 0.01 should be ignored if maxFrac is 1, but not if maxFrac
+ * is 2 or more. Note that roundingIncrements are rounded up in significance, so
+ * a roundingIncrement of 0.006 is treated like 0.01 for this determination, i.e.
+ * it should not be ignored if maxFrac is 2 or more (but a roundingIncrement of
+ * 0.005 is treated like 0.001 for significance).
+ *
+ * This test is needed for both NumberPropertyMapper::oldToNew and
+ * PatternStringUtils::propertiesToPatternString. In Java it cannot be
+ * exported by NumberPropertyMapper (package provate) so it is in
+ * PatternStringUtils, do the same in C.
+ *
+ * @param roundIncr
+ * The roundingIncrement to be checked. Must be non-zero.
+ * @param maxFrac
+ * The current maximum fraction digits value.
+ * @return true if roundIncr should be ignored for formatting.
+ */
+ static bool ignoreRoundingIncrement(double roundIncr, int32_t maxFrac);
+
+ /**
+ * Creates a pattern string from a property bag.
+ *
+ * <p>
+ * Since pattern strings support only a subset of the functionality available in a property bag, a new property bag
+ * created from the string returned by this function may not be the same as the original property bag.
+ *
+ * @param properties
+ * The property bag to serialize.
+ * @return A pattern string approximately serializing the property bag.
+ */
+ static UnicodeString propertiesToPatternString(const DecimalFormatProperties& properties,
+ UErrorCode& status);
+
+
+ /**
+ * Converts a pattern between standard notation and localized notation. Localized notation means that instead of
+ * using generic placeholders in the pattern, you use the corresponding locale-specific characters instead. For
+ * example, in locale <em>fr-FR</em>, the period in the pattern "0.000" means "decimal" in standard notation (as it
+ * does in every other locale), but it means "grouping" in localized notation.
+ *
+ * <p>
+ * A greedy string-substitution strategy is used to substitute locale symbols. If two symbols are ambiguous or have
+ * the same prefix, the result is not well-defined.
+ *
+ * <p>
+ * Locale symbols are not allowed to contain the ASCII quote character.
+ *
+ * <p>
+ * This method is provided for backwards compatibility and should not be used in any new code.
+ *
+ * TODO(C++): This method is not yet implemented.
+ *
+ * @param input
+ * The pattern to convert.
+ * @param symbols
+ * The symbols corresponding to the localized pattern.
+ * @param toLocalized
+ * true to convert from standard to localized notation; false to convert from localized to standard
+ * notation.
+ * @return The pattern expressed in the other notation.
+ */
+ 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,
+ PatternSignType patternSignType,
+ StandardPlural::Form plural, bool perMilleReplacesPercent,
+ UnicodeString& output);
+
+ static PatternSignType resolveSignDisplay(UNumberSignDisplay signDisplay, Signum signum);
+
+ private:
+ /** @return The number of chars inserted. */
+ static int escapePaddingString(UnicodeString input, UnicodeString& output, int startIndex,
+ UErrorCode& status);
+};
+
+} // namespace impl
+} // namespace number
+U_NAMESPACE_END
+
+
+#endif //__NUMBER_PATTERNSTRING_H__
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_rounding.cpp b/contrib/libs/icu/i18n/number_rounding.cpp
index 3ffce673ad..9481f9bcc2 100644
--- a/contrib/libs/icu/i18n/number_rounding.cpp
+++ b/contrib/libs/icu/i18n/number_rounding.cpp
@@ -1,441 +1,441 @@
-// © 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
-
-#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) {
- if (maxFrac == -1) {
- return INT32_MIN;
- }
- return -maxFrac;
-}
-
-int32_t getRoundingMagnitudeSignificant(const DecimalQuantity &value, int maxSig) {
- if (maxSig == -1) {
- return INT32_MIN;
- }
- int magnitude = value.isZeroish() ? 0 : value.getMagnitude();
- return magnitude - maxSig + 1;
-}
-
-int32_t getDisplayMagnitudeFraction(int minFrac) {
- if (minFrac == 0) {
- return INT32_MAX;
- }
- return -minFrac;
-}
-
-int32_t getDisplayMagnitudeSignificant(const DecimalQuantity &value, int minSig) {
- int magnitude = value.isZeroish() ? 0 : value.getMagnitude();
- return magnitude - minSig + 1;
-}
-
-}
-
-
-MultiplierProducer::~MultiplierProducer() = default;
-
-
-digits_t roundingutils::doubleFractionLength(double input, int8_t* singleDigit) {
- 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
- );
-
- if (singleDigit == nullptr) {
- // no-op
- } else if (length == 1) {
- *singleDigit = buffer[0] - '0';
- } else {
- *singleDigit = -1;
- }
-
- return static_cast<digits_t>(length - point);
-}
-
-
-Precision Precision::unlimited() {
- return Precision(RND_NONE, {}, kDefaultMode);
-}
-
-FractionPrecision Precision::integer() {
- return constructFraction(0, 0);
-}
-
-FractionPrecision Precision::fixedFraction(int32_t minMaxFractionPlaces) {
- if (minMaxFractionPlaces >= 0 && minMaxFractionPlaces <= kMaxIntFracSig) {
- return constructFraction(minMaxFractionPlaces, minMaxFractionPlaces);
- } else {
- return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
- }
-}
-
-FractionPrecision Precision::minFraction(int32_t minFractionPlaces) {
- if (minFractionPlaces >= 0 && minFractionPlaces <= kMaxIntFracSig) {
- return constructFraction(minFractionPlaces, -1);
- } else {
- return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
- }
-}
-
-FractionPrecision Precision::maxFraction(int32_t maxFractionPlaces) {
- if (maxFractionPlaces >= 0 && maxFractionPlaces <= kMaxIntFracSig) {
- return constructFraction(0, maxFractionPlaces);
- } else {
- return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
- }
-}
-
-FractionPrecision Precision::minMaxFraction(int32_t minFractionPlaces, int32_t maxFractionPlaces) {
- if (minFractionPlaces >= 0 && maxFractionPlaces <= kMaxIntFracSig &&
- minFractionPlaces <= maxFractionPlaces) {
- return constructFraction(minFractionPlaces, maxFractionPlaces);
- } else {
- return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
- }
-}
-
-Precision Precision::fixedSignificantDigits(int32_t minMaxSignificantDigits) {
- if (minMaxSignificantDigits >= 1 && minMaxSignificantDigits <= kMaxIntFracSig) {
- return constructSignificant(minMaxSignificantDigits, minMaxSignificantDigits);
- } else {
- return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
- }
-}
-
-Precision Precision::minSignificantDigits(int32_t minSignificantDigits) {
- if (minSignificantDigits >= 1 && minSignificantDigits <= kMaxIntFracSig) {
- return constructSignificant(minSignificantDigits, -1);
- } else {
- return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
- }
-}
-
-Precision Precision::maxSignificantDigits(int32_t maxSignificantDigits) {
- if (maxSignificantDigits >= 1 && maxSignificantDigits <= kMaxIntFracSig) {
- return constructSignificant(1, maxSignificantDigits);
- } else {
- return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
- }
-}
-
-Precision Precision::minMaxSignificantDigits(int32_t minSignificantDigits, int32_t maxSignificantDigits) {
- if (minSignificantDigits >= 1 && maxSignificantDigits <= kMaxIntFracSig &&
- minSignificantDigits <= maxSignificantDigits) {
- return constructSignificant(minSignificantDigits, maxSignificantDigits);
- } else {
- return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
- }
-}
-
-IncrementPrecision Precision::increment(double roundingIncrement) {
- if (roundingIncrement > 0.0) {
- return constructIncrement(roundingIncrement, 0);
- } else {
- return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
- }
-}
-
-CurrencyPrecision Precision::currency(UCurrencyUsage currencyUsage) {
- return constructCurrency(currencyUsage);
-}
-
-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);
- } else {
- return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
- }
-}
-
-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);
- } else {
- return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
- }
-}
-
-// Private method on base class
-Precision Precision::withCurrency(const CurrencyUnit &currency, 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();
- double increment = ucurr_getRoundingIncrementForUsage(isoCode, fUnion.currencyUsage, &status);
- int32_t minMaxFrac = ucurr_getDefaultFractionDigitsForUsage(
- isoCode, fUnion.currencyUsage, &status);
- if (increment != 0.0) {
- return constructIncrement(increment, minMaxFrac);
- } else {
- return constructFraction(minMaxFrac, minMaxFrac);
- }
-}
-
-// Public method on CurrencyPrecision subclass
-Precision CurrencyPrecision::withCurrency(const CurrencyUnit &currency) const {
- UErrorCode localStatus = U_ZERO_ERROR;
- Precision result = Precision::withCurrency(currency, localStatus);
- if (U_FAILURE(localStatus)) {
- return {localStatus};
- }
- return result;
-}
-
-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);
- } else {
- return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
- }
-}
-
-FractionPrecision Precision::constructFraction(int32_t minFrac, int32_t maxFrac) {
- FractionSignificantSettings settings;
- settings.fMinFrac = static_cast<digits_t>(minFrac);
- settings.fMaxFrac = static_cast<digits_t>(maxFrac);
- settings.fMinSig = -1;
- settings.fMaxSig = -1;
- PrecisionUnion union_;
- union_.fracSig = settings;
- return {RND_FRACTION, union_, kDefaultMode};
-}
-
-Precision Precision::constructSignificant(int32_t minSig, int32_t maxSig) {
- FractionSignificantSettings settings;
- settings.fMinFrac = -1;
- settings.fMaxFrac = -1;
- settings.fMinSig = static_cast<digits_t>(minSig);
- settings.fMaxSig = static_cast<digits_t>(maxSig);
- PrecisionUnion union_;
- union_.fracSig = settings;
- return {RND_SIGNIFICANT, union_, kDefaultMode};
-}
-
-Precision
-Precision::constructFractionSignificant(const FractionPrecision &base, int32_t minSig, int32_t maxSig) {
- FractionSignificantSettings settings = base.fUnion.fracSig;
- settings.fMinSig = static_cast<digits_t>(minSig);
- settings.fMaxSig = static_cast<digits_t>(maxSig);
- PrecisionUnion union_;
- union_.fracSig = settings;
- return {RND_FRACTION_SIGNIFICANT, union_, kDefaultMode};
-}
-
-IncrementPrecision Precision::constructIncrement(double increment, int32_t minFrac) {
- IncrementSettings settings;
- // Note: For number formatting, fIncrement is used for RND_INCREMENT but not
- // RND_INCREMENT_ONE or RND_INCREMENT_FIVE. However, fIncrement is used in all
- // three when constructing a skeleton.
- settings.fIncrement = increment;
- settings.fMinFrac = static_cast<digits_t>(minFrac);
- // One of the few pre-computed quantities:
- // Note: it is possible for minFrac to be more than maxFrac... (misleading)
- int8_t singleDigit;
- settings.fMaxFrac = roundingutils::doubleFractionLength(increment, &singleDigit);
- PrecisionUnion union_;
- union_.increment = settings;
- if (singleDigit == 1) {
- // NOTE: In C++, we must return the correct value type with the correct union.
- // It would be invalid to return a RND_FRACTION here because the methods on the
- // IncrementPrecision type assume that the union is backed by increment data.
- return {RND_INCREMENT_ONE, union_, kDefaultMode};
- } else if (singleDigit == 5) {
- return {RND_INCREMENT_FIVE, union_, kDefaultMode};
- } else {
- return {RND_INCREMENT, union_, kDefaultMode};
- }
-}
-
-CurrencyPrecision Precision::constructCurrency(UCurrencyUsage usage) {
- PrecisionUnion union_;
- union_.currencyUsage = usage;
- return {RND_CURRENCY, union_, kDefaultMode};
-}
-
-
-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() {
- return {};
-}
-
-bool RoundingImpl::isSignificantDigits() const {
- return fPrecision.fType == Precision::RND_SIGNIFICANT;
-}
-
-int32_t
-RoundingImpl::chooseMultiplierAndApply(impl::DecimalQuantity &input, const impl::MultiplierProducer &producer,
- UErrorCode &status) {
- // Do not call this method with zero, NaN, or infinity.
- U_ASSERT(!input.isZeroish());
-
- // Perform the first attempt at rounding.
- int magnitude = input.getMagnitude();
- int multiplier = producer.getMultiplier(magnitude);
- input.adjustMagnitude(multiplier);
- apply(input, status);
-
- // If the number rounded to zero, exit.
- if (input.isZeroish() || U_FAILURE(status)) {
- return multiplier;
- }
-
- // If the new magnitude after rounding is the same as it was before rounding, then we are done.
- // This case applies to most numbers.
- if (input.getMagnitude() == magnitude + multiplier) {
- return multiplier;
- }
-
- // If the above case DIDN'T apply, then we have a case like 99.9 -> 100 or 999.9 -> 1000:
- // The number rounded up to the next magnitude. Check if the multiplier changes; if it doesn't,
- // we do not need to make any more adjustments.
- int _multiplier = producer.getMultiplier(magnitude + 1);
- if (multiplier == _multiplier) {
- return multiplier;
- }
-
- // We have a case like 999.9 -> 1000, where the correct output is "1K", not "1000".
- // Fix the magnitude and re-apply the rounding strategy.
- input.adjustMagnitude(_multiplier - multiplier);
- apply(input, status);
- return _multiplier;
-}
-
-/** This is the method that contains the actual rounding logic. */
-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 Precision::RND_NONE:
- value.roundToInfinity();
- break;
-
- case Precision::RND_FRACTION:
- value.roundToMagnitude(
- getRoundingMagnitudeFraction(fPrecision.fUnion.fracSig.fMaxFrac),
- fRoundingMode,
- status);
- value.setMinFraction(
- uprv_max(0, -getDisplayMagnitudeFraction(fPrecision.fUnion.fracSig.fMinFrac)));
- break;
-
- case Precision::RND_SIGNIFICANT:
- value.roundToMagnitude(
- getRoundingMagnitudeSignificant(value, fPrecision.fUnion.fracSig.fMaxSig),
- fRoundingMode,
- status);
- value.setMinFraction(
- uprv_max(0, -getDisplayMagnitudeSignificant(value, fPrecision.fUnion.fracSig.fMinSig)));
- // Make sure that digits are displayed on zero.
- if (value.isZeroish() && fPrecision.fUnion.fracSig.fMinSig > 0) {
- value.setMinInteger(1);
- }
- break;
-
- 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,
- fPrecision.fUnion.fracSig.fMaxSig);
- roundingMag = uprv_max(roundingMag, candidate);
- } else {
- // Min Sig override
- int32_t candidate = getDisplayMagnitudeSignificant(
- value,
- fPrecision.fUnion.fracSig.fMinSig);
- roundingMag = uprv_min(roundingMag, candidate);
- }
- value.roundToMagnitude(roundingMag, fRoundingMode, status);
- value.setMinFraction(uprv_max(0, -displayMag));
- break;
- }
-
- case Precision::RND_INCREMENT:
- value.roundToIncrement(
- fPrecision.fUnion.increment.fIncrement,
- fRoundingMode,
- status);
- value.setMinFraction(fPrecision.fUnion.increment.fMinFrac);
- break;
-
- case Precision::RND_INCREMENT_ONE:
- value.roundToMagnitude(
- -fPrecision.fUnion.increment.fMaxFrac,
- fRoundingMode,
- status);
- value.setMinFraction(fPrecision.fUnion.increment.fMinFrac);
- break;
-
- case Precision::RND_INCREMENT_FIVE:
- value.roundToNickel(
- -fPrecision.fUnion.increment.fMaxFrac,
- fRoundingMode,
- status);
- value.setMinFraction(fPrecision.fUnion.increment.fMinFrac);
- break;
-
- case Precision::RND_CURRENCY:
- // Call .withCurrency() before .apply()!
- UPRV_UNREACHABLE;
-
- default:
- UPRV_UNREACHABLE;
- }
-}
-
-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(isSignificantDigits());
- U_ASSERT(value.isZeroish());
- value.setMinFraction(fPrecision.fUnion.fracSig.fMinSig - minInt);
-}
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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
+
+#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) {
+ if (maxFrac == -1) {
+ return INT32_MIN;
+ }
+ return -maxFrac;
+}
+
+int32_t getRoundingMagnitudeSignificant(const DecimalQuantity &value, int maxSig) {
+ if (maxSig == -1) {
+ return INT32_MIN;
+ }
+ int magnitude = value.isZeroish() ? 0 : value.getMagnitude();
+ return magnitude - maxSig + 1;
+}
+
+int32_t getDisplayMagnitudeFraction(int minFrac) {
+ if (minFrac == 0) {
+ return INT32_MAX;
+ }
+ return -minFrac;
+}
+
+int32_t getDisplayMagnitudeSignificant(const DecimalQuantity &value, int minSig) {
+ int magnitude = value.isZeroish() ? 0 : value.getMagnitude();
+ return magnitude - minSig + 1;
+}
+
+}
+
+
+MultiplierProducer::~MultiplierProducer() = default;
+
+
+digits_t roundingutils::doubleFractionLength(double input, int8_t* singleDigit) {
+ 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
+ );
+
+ if (singleDigit == nullptr) {
+ // no-op
+ } else if (length == 1) {
+ *singleDigit = buffer[0] - '0';
+ } else {
+ *singleDigit = -1;
+ }
+
+ return static_cast<digits_t>(length - point);
+}
+
+
+Precision Precision::unlimited() {
+ return Precision(RND_NONE, {}, kDefaultMode);
+}
+
+FractionPrecision Precision::integer() {
+ return constructFraction(0, 0);
+}
+
+FractionPrecision Precision::fixedFraction(int32_t minMaxFractionPlaces) {
+ if (minMaxFractionPlaces >= 0 && minMaxFractionPlaces <= kMaxIntFracSig) {
+ return constructFraction(minMaxFractionPlaces, minMaxFractionPlaces);
+ } else {
+ return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
+ }
+}
+
+FractionPrecision Precision::minFraction(int32_t minFractionPlaces) {
+ if (minFractionPlaces >= 0 && minFractionPlaces <= kMaxIntFracSig) {
+ return constructFraction(minFractionPlaces, -1);
+ } else {
+ return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
+ }
+}
+
+FractionPrecision Precision::maxFraction(int32_t maxFractionPlaces) {
+ if (maxFractionPlaces >= 0 && maxFractionPlaces <= kMaxIntFracSig) {
+ return constructFraction(0, maxFractionPlaces);
+ } else {
+ return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
+ }
+}
+
+FractionPrecision Precision::minMaxFraction(int32_t minFractionPlaces, int32_t maxFractionPlaces) {
+ if (minFractionPlaces >= 0 && maxFractionPlaces <= kMaxIntFracSig &&
+ minFractionPlaces <= maxFractionPlaces) {
+ return constructFraction(minFractionPlaces, maxFractionPlaces);
+ } else {
+ return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
+ }
+}
+
+Precision Precision::fixedSignificantDigits(int32_t minMaxSignificantDigits) {
+ if (minMaxSignificantDigits >= 1 && minMaxSignificantDigits <= kMaxIntFracSig) {
+ return constructSignificant(minMaxSignificantDigits, minMaxSignificantDigits);
+ } else {
+ return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
+ }
+}
+
+Precision Precision::minSignificantDigits(int32_t minSignificantDigits) {
+ if (minSignificantDigits >= 1 && minSignificantDigits <= kMaxIntFracSig) {
+ return constructSignificant(minSignificantDigits, -1);
+ } else {
+ return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
+ }
+}
+
+Precision Precision::maxSignificantDigits(int32_t maxSignificantDigits) {
+ if (maxSignificantDigits >= 1 && maxSignificantDigits <= kMaxIntFracSig) {
+ return constructSignificant(1, maxSignificantDigits);
+ } else {
+ return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
+ }
+}
+
+Precision Precision::minMaxSignificantDigits(int32_t minSignificantDigits, int32_t maxSignificantDigits) {
+ if (minSignificantDigits >= 1 && maxSignificantDigits <= kMaxIntFracSig &&
+ minSignificantDigits <= maxSignificantDigits) {
+ return constructSignificant(minSignificantDigits, maxSignificantDigits);
+ } else {
+ return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
+ }
+}
+
+IncrementPrecision Precision::increment(double roundingIncrement) {
+ if (roundingIncrement > 0.0) {
+ return constructIncrement(roundingIncrement, 0);
+ } else {
+ return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
+ }
+}
+
+CurrencyPrecision Precision::currency(UCurrencyUsage currencyUsage) {
+ return constructCurrency(currencyUsage);
+}
+
+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);
+ } else {
+ return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
+ }
+}
+
+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);
+ } else {
+ return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
+ }
+}
+
+// Private method on base class
+Precision Precision::withCurrency(const CurrencyUnit &currency, 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();
+ double increment = ucurr_getRoundingIncrementForUsage(isoCode, fUnion.currencyUsage, &status);
+ int32_t minMaxFrac = ucurr_getDefaultFractionDigitsForUsage(
+ isoCode, fUnion.currencyUsage, &status);
+ if (increment != 0.0) {
+ return constructIncrement(increment, minMaxFrac);
+ } else {
+ return constructFraction(minMaxFrac, minMaxFrac);
+ }
+}
+
+// Public method on CurrencyPrecision subclass
+Precision CurrencyPrecision::withCurrency(const CurrencyUnit &currency) const {
+ UErrorCode localStatus = U_ZERO_ERROR;
+ Precision result = Precision::withCurrency(currency, localStatus);
+ if (U_FAILURE(localStatus)) {
+ return {localStatus};
+ }
+ return result;
+}
+
+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);
+ } else {
+ return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
+ }
+}
+
+FractionPrecision Precision::constructFraction(int32_t minFrac, int32_t maxFrac) {
+ FractionSignificantSettings settings;
+ settings.fMinFrac = static_cast<digits_t>(minFrac);
+ settings.fMaxFrac = static_cast<digits_t>(maxFrac);
+ settings.fMinSig = -1;
+ settings.fMaxSig = -1;
+ PrecisionUnion union_;
+ union_.fracSig = settings;
+ return {RND_FRACTION, union_, kDefaultMode};
+}
+
+Precision Precision::constructSignificant(int32_t minSig, int32_t maxSig) {
+ FractionSignificantSettings settings;
+ settings.fMinFrac = -1;
+ settings.fMaxFrac = -1;
+ settings.fMinSig = static_cast<digits_t>(minSig);
+ settings.fMaxSig = static_cast<digits_t>(maxSig);
+ PrecisionUnion union_;
+ union_.fracSig = settings;
+ return {RND_SIGNIFICANT, union_, kDefaultMode};
+}
+
+Precision
+Precision::constructFractionSignificant(const FractionPrecision &base, int32_t minSig, int32_t maxSig) {
+ FractionSignificantSettings settings = base.fUnion.fracSig;
+ settings.fMinSig = static_cast<digits_t>(minSig);
+ settings.fMaxSig = static_cast<digits_t>(maxSig);
+ PrecisionUnion union_;
+ union_.fracSig = settings;
+ return {RND_FRACTION_SIGNIFICANT, union_, kDefaultMode};
+}
+
+IncrementPrecision Precision::constructIncrement(double increment, int32_t minFrac) {
+ IncrementSettings settings;
+ // Note: For number formatting, fIncrement is used for RND_INCREMENT but not
+ // RND_INCREMENT_ONE or RND_INCREMENT_FIVE. However, fIncrement is used in all
+ // three when constructing a skeleton.
+ settings.fIncrement = increment;
+ settings.fMinFrac = static_cast<digits_t>(minFrac);
+ // One of the few pre-computed quantities:
+ // Note: it is possible for minFrac to be more than maxFrac... (misleading)
+ int8_t singleDigit;
+ settings.fMaxFrac = roundingutils::doubleFractionLength(increment, &singleDigit);
+ PrecisionUnion union_;
+ union_.increment = settings;
+ if (singleDigit == 1) {
+ // NOTE: In C++, we must return the correct value type with the correct union.
+ // It would be invalid to return a RND_FRACTION here because the methods on the
+ // IncrementPrecision type assume that the union is backed by increment data.
+ return {RND_INCREMENT_ONE, union_, kDefaultMode};
+ } else if (singleDigit == 5) {
+ return {RND_INCREMENT_FIVE, union_, kDefaultMode};
+ } else {
+ return {RND_INCREMENT, union_, kDefaultMode};
+ }
+}
+
+CurrencyPrecision Precision::constructCurrency(UCurrencyUsage usage) {
+ PrecisionUnion union_;
+ union_.currencyUsage = usage;
+ return {RND_CURRENCY, union_, kDefaultMode};
+}
+
+
+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() {
+ return {};
+}
+
+bool RoundingImpl::isSignificantDigits() const {
+ return fPrecision.fType == Precision::RND_SIGNIFICANT;
+}
+
+int32_t
+RoundingImpl::chooseMultiplierAndApply(impl::DecimalQuantity &input, const impl::MultiplierProducer &producer,
+ UErrorCode &status) {
+ // Do not call this method with zero, NaN, or infinity.
+ U_ASSERT(!input.isZeroish());
+
+ // Perform the first attempt at rounding.
+ int magnitude = input.getMagnitude();
+ int multiplier = producer.getMultiplier(magnitude);
+ input.adjustMagnitude(multiplier);
+ apply(input, status);
+
+ // If the number rounded to zero, exit.
+ if (input.isZeroish() || U_FAILURE(status)) {
+ return multiplier;
+ }
+
+ // If the new magnitude after rounding is the same as it was before rounding, then we are done.
+ // This case applies to most numbers.
+ if (input.getMagnitude() == magnitude + multiplier) {
+ return multiplier;
+ }
+
+ // If the above case DIDN'T apply, then we have a case like 99.9 -> 100 or 999.9 -> 1000:
+ // The number rounded up to the next magnitude. Check if the multiplier changes; if it doesn't,
+ // we do not need to make any more adjustments.
+ int _multiplier = producer.getMultiplier(magnitude + 1);
+ if (multiplier == _multiplier) {
+ return multiplier;
+ }
+
+ // We have a case like 999.9 -> 1000, where the correct output is "1K", not "1000".
+ // Fix the magnitude and re-apply the rounding strategy.
+ input.adjustMagnitude(_multiplier - multiplier);
+ apply(input, status);
+ return _multiplier;
+}
+
+/** This is the method that contains the actual rounding logic. */
+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 Precision::RND_NONE:
+ value.roundToInfinity();
+ break;
+
+ case Precision::RND_FRACTION:
+ value.roundToMagnitude(
+ getRoundingMagnitudeFraction(fPrecision.fUnion.fracSig.fMaxFrac),
+ fRoundingMode,
+ status);
+ value.setMinFraction(
+ uprv_max(0, -getDisplayMagnitudeFraction(fPrecision.fUnion.fracSig.fMinFrac)));
+ break;
+
+ case Precision::RND_SIGNIFICANT:
+ value.roundToMagnitude(
+ getRoundingMagnitudeSignificant(value, fPrecision.fUnion.fracSig.fMaxSig),
+ fRoundingMode,
+ status);
+ value.setMinFraction(
+ uprv_max(0, -getDisplayMagnitudeSignificant(value, fPrecision.fUnion.fracSig.fMinSig)));
+ // Make sure that digits are displayed on zero.
+ if (value.isZeroish() && fPrecision.fUnion.fracSig.fMinSig > 0) {
+ value.setMinInteger(1);
+ }
+ break;
+
+ 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,
+ fPrecision.fUnion.fracSig.fMaxSig);
+ roundingMag = uprv_max(roundingMag, candidate);
+ } else {
+ // Min Sig override
+ int32_t candidate = getDisplayMagnitudeSignificant(
+ value,
+ fPrecision.fUnion.fracSig.fMinSig);
+ roundingMag = uprv_min(roundingMag, candidate);
+ }
+ value.roundToMagnitude(roundingMag, fRoundingMode, status);
+ value.setMinFraction(uprv_max(0, -displayMag));
+ break;
+ }
+
+ case Precision::RND_INCREMENT:
+ value.roundToIncrement(
+ fPrecision.fUnion.increment.fIncrement,
+ fRoundingMode,
+ status);
+ value.setMinFraction(fPrecision.fUnion.increment.fMinFrac);
+ break;
+
+ case Precision::RND_INCREMENT_ONE:
+ value.roundToMagnitude(
+ -fPrecision.fUnion.increment.fMaxFrac,
+ fRoundingMode,
+ status);
+ value.setMinFraction(fPrecision.fUnion.increment.fMinFrac);
+ break;
+
+ case Precision::RND_INCREMENT_FIVE:
+ value.roundToNickel(
+ -fPrecision.fUnion.increment.fMaxFrac,
+ fRoundingMode,
+ status);
+ value.setMinFraction(fPrecision.fUnion.increment.fMinFrac);
+ break;
+
+ case Precision::RND_CURRENCY:
+ // Call .withCurrency() before .apply()!
+ UPRV_UNREACHABLE;
+
+ default:
+ UPRV_UNREACHABLE;
+ }
+}
+
+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(isSignificantDigits());
+ U_ASSERT(value.isZeroish());
+ value.setMinFraction(fPrecision.fUnion.fracSig.fMinSig - minInt);
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_roundingutils.h b/contrib/libs/icu/i18n/number_roundingutils.h
index 3e37f31954..1a13504b89 100644
--- a/contrib/libs/icu/i18n/number_roundingutils.h
+++ b/contrib/libs/icu/i18n/number_roundingutils.h
@@ -1,199 +1,199 @@
-// © 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_ROUNDINGUTILS_H__
-#define __NUMBER_ROUNDINGUTILS_H__
-
-#include "number_types.h"
-
-U_NAMESPACE_BEGIN
-namespace number {
-namespace impl {
-namespace roundingutils {
-
-enum Section {
- SECTION_LOWER_EDGE = -1,
- SECTION_UPPER_EDGE = -2,
- SECTION_LOWER = 1,
- SECTION_MIDPOINT = 2,
- SECTION_UPPER = 3
-};
-
-/**
- * Converts a rounding mode and metadata about the quantity being rounded to a boolean determining
- * whether the value should be rounded toward infinity or toward zero.
- *
- * <p>The parameters are of type int because benchmarks on an x86-64 processor against OpenJDK
- * showed that ints were demonstrably faster than enums in switch statements.
- *
- * @param isEven Whether the digit immediately before the rounding magnitude is even.
- * @param isNegative Whether the quantity is negative.
- * @param section Whether the part of the quantity to the right of the rounding magnitude is
- * exactly halfway between two digits, whether it is in the lower part (closer to zero), or
- * whether it is in the upper part (closer to infinity). See {@link #SECTION_LOWER}, {@link
- * #SECTION_MIDPOINT}, and {@link #SECTION_UPPER}.
- * @param roundingMode The integer version of the {@link RoundingMode}, which you can get via
- * {@link RoundingMode#ordinal}.
- * @param status Error code, set to U_FORMAT_INEXACT_ERROR if the rounding mode is kRoundUnnecessary.
- * @return true if the number should be rounded toward zero; false if it should be rounded toward
- * infinity.
- */
-inline bool
-getRoundingDirection(bool isEven, bool isNegative, Section section, RoundingMode roundingMode,
- UErrorCode &status) {
- switch (roundingMode) {
- case RoundingMode::UNUM_ROUND_UP:
- // round away from zero
- return false;
-
- case RoundingMode::UNUM_ROUND_DOWN:
- // round toward zero
- return true;
-
- case RoundingMode::UNUM_ROUND_CEILING:
- // round toward positive infinity
- return isNegative;
-
- case RoundingMode::UNUM_ROUND_FLOOR:
- // round toward negative infinity
- return !isNegative;
-
- case RoundingMode::UNUM_ROUND_HALFUP:
- switch (section) {
- case SECTION_MIDPOINT:
- return false;
- case SECTION_LOWER:
- return true;
- case SECTION_UPPER:
- return false;
- default:
- break;
- }
- break;
-
- case RoundingMode::UNUM_ROUND_HALFDOWN:
- switch (section) {
- case SECTION_MIDPOINT:
- return true;
- case SECTION_LOWER:
- return true;
- case SECTION_UPPER:
- return false;
- default:
- break;
- }
- break;
-
- case RoundingMode::UNUM_ROUND_HALFEVEN:
- switch (section) {
- case SECTION_MIDPOINT:
- return isEven;
- case SECTION_LOWER:
- return true;
- case SECTION_UPPER:
- return false;
- default:
- break;
- }
- break;
-
- default:
- break;
- }
-
- status = U_FORMAT_INEXACT_ERROR;
- return false;
-}
-
-/**
- * Gets whether the given rounding mode's rounding boundary is at the midpoint. The rounding
- * boundary is the point at which a number switches from being rounded down to being rounded up.
- * For example, with rounding mode HALF_EVEN, HALF_UP, or HALF_DOWN, the rounding boundary is at
- * the midpoint, and this function would return true. However, for UP, DOWN, CEILING, and FLOOR,
- * the rounding boundary is at the "edge", and this function would return false.
- *
- * @param roundingMode The integer version of the {@link RoundingMode}.
- * @return true if rounding mode is HALF_EVEN, HALF_UP, or HALF_DOWN; false otherwise.
- */
-inline bool roundsAtMidpoint(int roundingMode) {
- switch (roundingMode) {
- case RoundingMode::UNUM_ROUND_UP:
- case RoundingMode::UNUM_ROUND_DOWN:
- case RoundingMode::UNUM_ROUND_CEILING:
- case RoundingMode::UNUM_ROUND_FLOOR:
- return false;
-
- default:
- return true;
- }
-}
-
-/**
- * Computes the number of fraction digits in a double. Used for computing maxFrac for an increment.
- * Calls into the DoubleToStringConverter library to do so.
- *
- * @param singleDigit An output parameter; set to a number if that is the
- * only digit in the double, or -1 if there is more than one digit.
- */
-digits_t doubleFractionLength(double input, int8_t* singleDigit);
-
-} // 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; // defaults to pass-through rounder
-
- 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.
- *
- * <p>
- * 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 = true; // default value
-};
-
-
-} // namespace impl
-} // namespace number
-U_NAMESPACE_END
-
-#endif //__NUMBER_ROUNDINGUTILS_H__
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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_ROUNDINGUTILS_H__
+#define __NUMBER_ROUNDINGUTILS_H__
+
+#include "number_types.h"
+
+U_NAMESPACE_BEGIN
+namespace number {
+namespace impl {
+namespace roundingutils {
+
+enum Section {
+ SECTION_LOWER_EDGE = -1,
+ SECTION_UPPER_EDGE = -2,
+ SECTION_LOWER = 1,
+ SECTION_MIDPOINT = 2,
+ SECTION_UPPER = 3
+};
+
+/**
+ * Converts a rounding mode and metadata about the quantity being rounded to a boolean determining
+ * whether the value should be rounded toward infinity or toward zero.
+ *
+ * <p>The parameters are of type int because benchmarks on an x86-64 processor against OpenJDK
+ * showed that ints were demonstrably faster than enums in switch statements.
+ *
+ * @param isEven Whether the digit immediately before the rounding magnitude is even.
+ * @param isNegative Whether the quantity is negative.
+ * @param section Whether the part of the quantity to the right of the rounding magnitude is
+ * exactly halfway between two digits, whether it is in the lower part (closer to zero), or
+ * whether it is in the upper part (closer to infinity). See {@link #SECTION_LOWER}, {@link
+ * #SECTION_MIDPOINT}, and {@link #SECTION_UPPER}.
+ * @param roundingMode The integer version of the {@link RoundingMode}, which you can get via
+ * {@link RoundingMode#ordinal}.
+ * @param status Error code, set to U_FORMAT_INEXACT_ERROR if the rounding mode is kRoundUnnecessary.
+ * @return true if the number should be rounded toward zero; false if it should be rounded toward
+ * infinity.
+ */
+inline bool
+getRoundingDirection(bool isEven, bool isNegative, Section section, RoundingMode roundingMode,
+ UErrorCode &status) {
+ switch (roundingMode) {
+ case RoundingMode::UNUM_ROUND_UP:
+ // round away from zero
+ return false;
+
+ case RoundingMode::UNUM_ROUND_DOWN:
+ // round toward zero
+ return true;
+
+ case RoundingMode::UNUM_ROUND_CEILING:
+ // round toward positive infinity
+ return isNegative;
+
+ case RoundingMode::UNUM_ROUND_FLOOR:
+ // round toward negative infinity
+ return !isNegative;
+
+ case RoundingMode::UNUM_ROUND_HALFUP:
+ switch (section) {
+ case SECTION_MIDPOINT:
+ return false;
+ case SECTION_LOWER:
+ return true;
+ case SECTION_UPPER:
+ return false;
+ default:
+ break;
+ }
+ break;
+
+ case RoundingMode::UNUM_ROUND_HALFDOWN:
+ switch (section) {
+ case SECTION_MIDPOINT:
+ return true;
+ case SECTION_LOWER:
+ return true;
+ case SECTION_UPPER:
+ return false;
+ default:
+ break;
+ }
+ break;
+
+ case RoundingMode::UNUM_ROUND_HALFEVEN:
+ switch (section) {
+ case SECTION_MIDPOINT:
+ return isEven;
+ case SECTION_LOWER:
+ return true;
+ case SECTION_UPPER:
+ return false;
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ status = U_FORMAT_INEXACT_ERROR;
+ return false;
+}
+
+/**
+ * Gets whether the given rounding mode's rounding boundary is at the midpoint. The rounding
+ * boundary is the point at which a number switches from being rounded down to being rounded up.
+ * For example, with rounding mode HALF_EVEN, HALF_UP, or HALF_DOWN, the rounding boundary is at
+ * the midpoint, and this function would return true. However, for UP, DOWN, CEILING, and FLOOR,
+ * the rounding boundary is at the "edge", and this function would return false.
+ *
+ * @param roundingMode The integer version of the {@link RoundingMode}.
+ * @return true if rounding mode is HALF_EVEN, HALF_UP, or HALF_DOWN; false otherwise.
+ */
+inline bool roundsAtMidpoint(int roundingMode) {
+ switch (roundingMode) {
+ case RoundingMode::UNUM_ROUND_UP:
+ case RoundingMode::UNUM_ROUND_DOWN:
+ case RoundingMode::UNUM_ROUND_CEILING:
+ case RoundingMode::UNUM_ROUND_FLOOR:
+ return false;
+
+ default:
+ return true;
+ }
+}
+
+/**
+ * Computes the number of fraction digits in a double. Used for computing maxFrac for an increment.
+ * Calls into the DoubleToStringConverter library to do so.
+ *
+ * @param singleDigit An output parameter; set to a number if that is the
+ * only digit in the double, or -1 if there is more than one digit.
+ */
+digits_t doubleFractionLength(double input, int8_t* singleDigit);
+
+} // 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; // defaults to pass-through rounder
+
+ 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.
+ *
+ * <p>
+ * 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 = true; // default value
+};
+
+
+} // namespace impl
+} // namespace number
+U_NAMESPACE_END
+
+#endif //__NUMBER_ROUNDINGUTILS_H__
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_scientific.cpp b/contrib/libs/icu/i18n/number_scientific.cpp
index 527ffbf78d..3718dab2dc 100644
--- a/contrib/libs/icu/i18n/number_scientific.cpp
+++ b/contrib/libs/icu/i18n/number_scientific.cpp
@@ -1,177 +1,177 @@
-// © 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
-
-#include <cstdlib>
-#include "number_scientific.h"
-#include "number_utils.h"
-#include "formatted_string_builder.h"
-#include "unicode/unum.h"
-#include "number_microprops.h"
-
-using namespace icu;
-using namespace icu::number;
-using namespace icu::number::impl;
-
-// NOTE: The object lifecycle of ScientificModifier and ScientificHandler differ greatly in Java and C++.
-//
-// During formatting, we need to provide an object with state (the exponent) as the inner modifier.
-//
-// In Java, where the priority is put on reducing object creations, the unsafe code path re-uses the
-// ScientificHandler as a ScientificModifier, and the safe code path pre-computes 25 ScientificModifier
-// instances. This scheme reduces the number of object creations by 1 in both safe and unsafe.
-//
-// In C++, MicroProps provides a pre-allocated ScientificModifier, and ScientificHandler simply populates
-// the state (the exponent) into that ScientificModifier. There is no difference between safe and unsafe.
-
-ScientificModifier::ScientificModifier() : fExponent(0), fHandler(nullptr) {}
-
-void ScientificModifier::set(int32_t exponent, const ScientificHandler *handler) {
- // ScientificModifier should be set only once.
- U_ASSERT(fHandler == nullptr);
- fExponent = exponent;
- fHandler = handler;
-}
-
-int32_t ScientificModifier::apply(FormattedStringBuilder &output, int32_t /*leftIndex*/, int32_t rightIndex,
- UErrorCode &status) const {
- // FIXME: Localized exponent separator location.
- int i = rightIndex;
- // Append the exponent separator and sign
- i += output.insert(
- i,
- fHandler->fSymbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kExponentialSymbol),
- {UFIELD_CATEGORY_NUMBER, UNUM_EXPONENT_SYMBOL_FIELD},
- status);
- if (fExponent < 0 && fHandler->fSettings.fExponentSignDisplay != UNUM_SIGN_NEVER) {
- i += output.insert(
- i,
- fHandler->fSymbols
- ->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kMinusSignSymbol),
- {UFIELD_CATEGORY_NUMBER, UNUM_EXPONENT_SIGN_FIELD},
- status);
- } else if (fExponent >= 0 && fHandler->fSettings.fExponentSignDisplay == UNUM_SIGN_ALWAYS) {
- i += output.insert(
- i,
- fHandler->fSymbols
- ->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPlusSignSymbol),
- {UFIELD_CATEGORY_NUMBER, UNUM_EXPONENT_SIGN_FIELD},
- status);
- }
- // Append the exponent digits (using a simple inline algorithm)
- int32_t disp = std::abs(fExponent);
- for (int j = 0; j < fHandler->fSettings.fMinExponentDigits || disp > 0; j++, disp /= 10) {
- auto d = static_cast<int8_t>(disp % 10);
- i += utils::insertDigitFromSymbols(
- output,
- i - j,
- d,
- *fHandler->fSymbols,
- {UFIELD_CATEGORY_NUMBER, UNUM_EXPONENT_FIELD},
- status);
- }
- return i - rightIndex;
-}
-
-int32_t ScientificModifier::getPrefixLength() const {
- // TODO: Localized exponent separator location.
- return 0;
-}
-
-int32_t ScientificModifier::getCodePointCount() const {
- // NOTE: This method is only called one place, NumberRangeFormatterImpl.
- // The call site only cares about != 0 and != 1.
- // Return a very large value so that if this method is used elsewhere, we should notice.
- return 999;
-}
-
-bool ScientificModifier::isStrong() const {
- // Scientific is always strong
- return true;
-}
-
-bool ScientificModifier::containsField(Field field) const {
- (void)field;
- // This method is not used for inner modifiers.
- UPRV_UNREACHABLE;
-}
-
-void ScientificModifier::getParameters(Parameters& output) const {
- // Not part of any plural sets
- output.obj = nullptr;
-}
-
-bool ScientificModifier::semanticallyEquivalent(const Modifier& other) const {
- auto* _other = dynamic_cast<const ScientificModifier*>(&other);
- if (_other == nullptr) {
- return false;
- }
- // TODO: Check for locale symbols and settings as well? Could be less efficient.
- return fExponent == _other->fExponent;
-}
-
-// Note: Visual Studio does not compile this function without full name space. Why?
-icu::number::impl::ScientificHandler::ScientificHandler(const Notation *notation, const DecimalFormatSymbols *symbols,
- const MicroPropsGenerator *parent) :
- fSettings(notation->fUnion.scientific), fSymbols(symbols), fParent(parent) {}
-
-void ScientificHandler::processQuantity(DecimalQuantity &quantity, MicroProps &micros,
- UErrorCode &status) const {
- fParent->processQuantity(quantity, micros, status);
- if (U_FAILURE(status)) { return; }
-
- // Do not apply scientific notation to special doubles
- if (quantity.isInfinite() || quantity.isNaN()) {
- micros.modInner = &micros.helpers.emptyStrongModifier;
- return;
- }
-
- // Treat zero as if it had magnitude 0
- int32_t exponent;
- if (quantity.isZeroish()) {
- if (fSettings.fRequireMinInt && micros.rounder.isSignificantDigits()) {
- // Show "00.000E0" on pattern "00.000E0"
- micros.rounder.apply(quantity, fSettings.fEngineeringInterval, status);
- exponent = 0;
- } else {
- micros.rounder.apply(quantity, status);
- exponent = 0;
- }
- } else {
- 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;
-
- // Change the exponent only after we select appropriate plural form
- // for formatting purposes so that we preserve expected formatted
- // string behavior.
- quantity.adjustExponent(exponent);
-
- // We already performed rounding. Do not perform it again.
- micros.rounder = RoundingImpl::passThrough();
-}
-
-int32_t ScientificHandler::getMultiplier(int32_t magnitude) const {
- int32_t interval = fSettings.fEngineeringInterval;
- int32_t digitsShown;
- if (fSettings.fRequireMinInt) {
- // For patterns like "000.00E0" and ".00E0"
- digitsShown = interval;
- } else if (interval <= 1) {
- // For patterns like "0.00E0" and "@@@E0"
- digitsShown = 1;
- } else {
- // For patterns like "##0.00"
- digitsShown = ((magnitude % interval + interval) % interval) + 1;
- }
- return digitsShown - magnitude - 1;
-}
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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
+
+#include <cstdlib>
+#include "number_scientific.h"
+#include "number_utils.h"
+#include "formatted_string_builder.h"
+#include "unicode/unum.h"
+#include "number_microprops.h"
+
+using namespace icu;
+using namespace icu::number;
+using namespace icu::number::impl;
+
+// NOTE: The object lifecycle of ScientificModifier and ScientificHandler differ greatly in Java and C++.
+//
+// During formatting, we need to provide an object with state (the exponent) as the inner modifier.
+//
+// In Java, where the priority is put on reducing object creations, the unsafe code path re-uses the
+// ScientificHandler as a ScientificModifier, and the safe code path pre-computes 25 ScientificModifier
+// instances. This scheme reduces the number of object creations by 1 in both safe and unsafe.
+//
+// In C++, MicroProps provides a pre-allocated ScientificModifier, and ScientificHandler simply populates
+// the state (the exponent) into that ScientificModifier. There is no difference between safe and unsafe.
+
+ScientificModifier::ScientificModifier() : fExponent(0), fHandler(nullptr) {}
+
+void ScientificModifier::set(int32_t exponent, const ScientificHandler *handler) {
+ // ScientificModifier should be set only once.
+ U_ASSERT(fHandler == nullptr);
+ fExponent = exponent;
+ fHandler = handler;
+}
+
+int32_t ScientificModifier::apply(FormattedStringBuilder &output, int32_t /*leftIndex*/, int32_t rightIndex,
+ UErrorCode &status) const {
+ // FIXME: Localized exponent separator location.
+ int i = rightIndex;
+ // Append the exponent separator and sign
+ i += output.insert(
+ i,
+ fHandler->fSymbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kExponentialSymbol),
+ {UFIELD_CATEGORY_NUMBER, UNUM_EXPONENT_SYMBOL_FIELD},
+ status);
+ if (fExponent < 0 && fHandler->fSettings.fExponentSignDisplay != UNUM_SIGN_NEVER) {
+ i += output.insert(
+ i,
+ fHandler->fSymbols
+ ->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kMinusSignSymbol),
+ {UFIELD_CATEGORY_NUMBER, UNUM_EXPONENT_SIGN_FIELD},
+ status);
+ } else if (fExponent >= 0 && fHandler->fSettings.fExponentSignDisplay == UNUM_SIGN_ALWAYS) {
+ i += output.insert(
+ i,
+ fHandler->fSymbols
+ ->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPlusSignSymbol),
+ {UFIELD_CATEGORY_NUMBER, UNUM_EXPONENT_SIGN_FIELD},
+ status);
+ }
+ // Append the exponent digits (using a simple inline algorithm)
+ int32_t disp = std::abs(fExponent);
+ for (int j = 0; j < fHandler->fSettings.fMinExponentDigits || disp > 0; j++, disp /= 10) {
+ auto d = static_cast<int8_t>(disp % 10);
+ i += utils::insertDigitFromSymbols(
+ output,
+ i - j,
+ d,
+ *fHandler->fSymbols,
+ {UFIELD_CATEGORY_NUMBER, UNUM_EXPONENT_FIELD},
+ status);
+ }
+ return i - rightIndex;
+}
+
+int32_t ScientificModifier::getPrefixLength() const {
+ // TODO: Localized exponent separator location.
+ return 0;
+}
+
+int32_t ScientificModifier::getCodePointCount() const {
+ // NOTE: This method is only called one place, NumberRangeFormatterImpl.
+ // The call site only cares about != 0 and != 1.
+ // Return a very large value so that if this method is used elsewhere, we should notice.
+ return 999;
+}
+
+bool ScientificModifier::isStrong() const {
+ // Scientific is always strong
+ return true;
+}
+
+bool ScientificModifier::containsField(Field field) const {
+ (void)field;
+ // This method is not used for inner modifiers.
+ UPRV_UNREACHABLE;
+}
+
+void ScientificModifier::getParameters(Parameters& output) const {
+ // Not part of any plural sets
+ output.obj = nullptr;
+}
+
+bool ScientificModifier::semanticallyEquivalent(const Modifier& other) const {
+ auto* _other = dynamic_cast<const ScientificModifier*>(&other);
+ if (_other == nullptr) {
+ return false;
+ }
+ // TODO: Check for locale symbols and settings as well? Could be less efficient.
+ return fExponent == _other->fExponent;
+}
+
+// Note: Visual Studio does not compile this function without full name space. Why?
+icu::number::impl::ScientificHandler::ScientificHandler(const Notation *notation, const DecimalFormatSymbols *symbols,
+ const MicroPropsGenerator *parent) :
+ fSettings(notation->fUnion.scientific), fSymbols(symbols), fParent(parent) {}
+
+void ScientificHandler::processQuantity(DecimalQuantity &quantity, MicroProps &micros,
+ UErrorCode &status) const {
+ fParent->processQuantity(quantity, micros, status);
+ if (U_FAILURE(status)) { return; }
+
+ // Do not apply scientific notation to special doubles
+ if (quantity.isInfinite() || quantity.isNaN()) {
+ micros.modInner = &micros.helpers.emptyStrongModifier;
+ return;
+ }
+
+ // Treat zero as if it had magnitude 0
+ int32_t exponent;
+ if (quantity.isZeroish()) {
+ if (fSettings.fRequireMinInt && micros.rounder.isSignificantDigits()) {
+ // Show "00.000E0" on pattern "00.000E0"
+ micros.rounder.apply(quantity, fSettings.fEngineeringInterval, status);
+ exponent = 0;
+ } else {
+ micros.rounder.apply(quantity, status);
+ exponent = 0;
+ }
+ } else {
+ 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;
+
+ // Change the exponent only after we select appropriate plural form
+ // for formatting purposes so that we preserve expected formatted
+ // string behavior.
+ quantity.adjustExponent(exponent);
+
+ // We already performed rounding. Do not perform it again.
+ micros.rounder = RoundingImpl::passThrough();
+}
+
+int32_t ScientificHandler::getMultiplier(int32_t magnitude) const {
+ int32_t interval = fSettings.fEngineeringInterval;
+ int32_t digitsShown;
+ if (fSettings.fRequireMinInt) {
+ // For patterns like "000.00E0" and ".00E0"
+ digitsShown = interval;
+ } else if (interval <= 1) {
+ // For patterns like "0.00E0" and "@@@E0"
+ digitsShown = 1;
+ } else {
+ // For patterns like "##0.00"
+ digitsShown = ((magnitude % interval + interval) % interval) + 1;
+ }
+ return digitsShown - magnitude - 1;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_scientific.h b/contrib/libs/icu/i18n/number_scientific.h
index a55d5ed1d4..0d99deea4c 100644
--- a/contrib/libs/icu/i18n/number_scientific.h
+++ b/contrib/libs/icu/i18n/number_scientific.h
@@ -1,68 +1,68 @@
-// © 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_SCIENTIFIC_H__
-#define __NUMBER_SCIENTIFIC_H__
-
-#include "number_types.h"
-
-U_NAMESPACE_BEGIN namespace number {
-namespace impl {
-
-// Forward-declare
-class ScientificHandler;
-
-class U_I18N_API ScientificModifier : public UMemory, public Modifier {
- public:
- ScientificModifier();
-
- void set(int32_t exponent, const ScientificHandler *handler);
-
- int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
- UErrorCode &status) const U_OVERRIDE;
-
- int32_t getPrefixLength() const U_OVERRIDE;
-
- int32_t getCodePointCount() const U_OVERRIDE;
-
- bool isStrong() const U_OVERRIDE;
-
- bool containsField(Field field) const U_OVERRIDE;
-
- void getParameters(Parameters& output) const U_OVERRIDE;
-
- bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
-
- private:
- int32_t fExponent;
- const ScientificHandler *fHandler;
-};
-
-class ScientificHandler : public UMemory, public MicroPropsGenerator, public MultiplierProducer {
- public:
- ScientificHandler(const Notation *notation, const DecimalFormatSymbols *symbols,
- const MicroPropsGenerator *parent);
-
- void
- processQuantity(DecimalQuantity &quantity, MicroProps &micros, UErrorCode &status) const U_OVERRIDE;
-
- int32_t getMultiplier(int32_t magnitude) const U_OVERRIDE;
-
- private:
- const Notation::ScientificSettings& fSettings;
- const DecimalFormatSymbols *fSymbols;
- const MicroPropsGenerator *fParent;
-
- friend class ScientificModifier;
-};
-
-} // namespace impl
-} // namespace number
-U_NAMESPACE_END
-
-#endif //__NUMBER_SCIENTIFIC_H__
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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_SCIENTIFIC_H__
+#define __NUMBER_SCIENTIFIC_H__
+
+#include "number_types.h"
+
+U_NAMESPACE_BEGIN namespace number {
+namespace impl {
+
+// Forward-declare
+class ScientificHandler;
+
+class U_I18N_API ScientificModifier : public UMemory, public Modifier {
+ public:
+ ScientificModifier();
+
+ void set(int32_t exponent, const ScientificHandler *handler);
+
+ int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
+ UErrorCode &status) const U_OVERRIDE;
+
+ int32_t getPrefixLength() const U_OVERRIDE;
+
+ int32_t getCodePointCount() const U_OVERRIDE;
+
+ bool isStrong() const U_OVERRIDE;
+
+ bool containsField(Field field) const U_OVERRIDE;
+
+ void getParameters(Parameters& output) const U_OVERRIDE;
+
+ bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
+
+ private:
+ int32_t fExponent;
+ const ScientificHandler *fHandler;
+};
+
+class ScientificHandler : public UMemory, public MicroPropsGenerator, public MultiplierProducer {
+ public:
+ ScientificHandler(const Notation *notation, const DecimalFormatSymbols *symbols,
+ const MicroPropsGenerator *parent);
+
+ void
+ processQuantity(DecimalQuantity &quantity, MicroProps &micros, UErrorCode &status) const U_OVERRIDE;
+
+ int32_t getMultiplier(int32_t magnitude) const U_OVERRIDE;
+
+ private:
+ const Notation::ScientificSettings& fSettings;
+ const DecimalFormatSymbols *fSymbols;
+ const MicroPropsGenerator *fParent;
+
+ friend class ScientificModifier;
+};
+
+} // namespace impl
+} // namespace number
+U_NAMESPACE_END
+
+#endif //__NUMBER_SCIENTIFIC_H__
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_skeletons.cpp b/contrib/libs/icu/i18n/number_skeletons.cpp
index 4ba2647986..7b4b20ec6c 100644
--- a/contrib/libs/icu/i18n/number_skeletons.cpp
+++ b/contrib/libs/icu/i18n/number_skeletons.cpp
@@ -1,1731 +1,1731 @@
-// © 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"
-#include "string_segment.h"
-#include "unicode/errorcode.h"
-#include "util.h"
-#include "measunit_impl.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"unit", STEM_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; }
-
- // Section 3 (concise tokens):
- b.add(u"K", STEM_COMPACT_SHORT, status);
- b.add(u"KK", STEM_COMPACT_LONG, status);
- b.add(u"%", STEM_PERCENT, status);
- b.add(u"%x100", STEM_PERCENT_100, status);
- b.add(u",_", STEM_GROUP_OFF, status);
- b.add(u",?", STEM_GROUP_MIN2, status);
- b.add(u",!", STEM_GROUP_ON_ALIGNED, status);
- b.add(u"+!", STEM_SIGN_ALWAYS, status);
- b.add(u"+_", STEM_SIGN_NEVER, status);
- b.add(u"()", STEM_SIGN_ACCOUNTING, status);
- b.add(u"()!", STEM_SIGN_ACCOUNTING_ALWAYS, status);
- b.add(u"+?", STEM_SIGN_EXCEPT_ZERO, status);
- b.add(u"()?", STEM_SIGN_ACCOUNTING_EXCEPT_ZERO, 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<char16_t*>(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 */ \
-UPRV_BLOCK_MACRO_BEGIN { \
- if ((seen).field) { \
- (status) = U_NUMBER_SKELETON_SYNTAX_ERROR; \
- return STATE_NULL; \
- } \
- (seen).field = true; \
-} UPRV_BLOCK_MACRO_END
-
-
-#define SKELETON_UCHAR_TO_CHAR(dest, src, start, end, status) (void)(dest); \
-UPRV_BLOCK_MACRO_BEGIN { \
- 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; \
- } \
-} UPRV_BLOCK_MACRO_END
-
-
-} // 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:
- UPRV_UNREACHABLE;
- }
-}
-
-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:
- UPRV_UNREACHABLE;
- }
-}
-
-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:
- UPRV_UNREACHABLE;
- }
-}
-
-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:
- UPRV_UNREACHABLE;
- }
-}
-
-UNumberGroupingStrategy 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:
- UPRV_UNREACHABLE;
- }
-}
-
-void enum_to_stem_string::groupingStrategy(UNumberGroupingStrategy 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:
- UPRV_UNREACHABLE;
- }
-}
-
-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:
- UPRV_UNREACHABLE;
- }
-}
-
-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:
- UPRV_UNREACHABLE;
- }
-}
-
-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:
- UPRV_UNREACHABLE;
- }
-}
-
-
-UnlocalizedNumberFormatter skeleton::create(
- const UnicodeString& skeletonString, UParseError* perror, UErrorCode& status) {
-
- // Initialize perror
- if (perror != nullptr) {
- perror->line = 0;
- perror->offset = -1;
- perror->preContext[0] = 0;
- perror->postContext[0] = 0;
- }
-
- umtx_initOnce(gNumberSkeletonsInitOnce, &initNumberSkeletons, status);
- if (U_FAILURE(status)) {
- return {};
- }
-
- int32_t errOffset;
- MacroProps macros = parseSkeleton(skeletonString, errOffset, status);
- if (U_SUCCESS(status)) {
- return NumberFormatter::with().macros(macros);
- }
-
- if (perror == nullptr) {
- return {};
- }
-
- // Populate the UParseError with the error location
- perror->offset = errOffset;
- int32_t contextStart = uprv_max(0, errOffset - U_PARSE_CONTEXT_LEN + 1);
- int32_t contextEnd = uprv_min(skeletonString.length(), errOffset + U_PARSE_CONTEXT_LEN - 1);
- skeletonString.extract(contextStart, errOffset - contextStart, perror->preContext, 0);
- perror->preContext[errOffset - contextStart] = 0;
- skeletonString.extract(errOffset, contextEnd - errOffset, perror->postContext, 0);
- perror->postContext[contextEnd - errOffset] = 0;
- return {};
-}
-
-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, int32_t& errOffset, UErrorCode& status) {
- U_ASSERT(U_SUCCESS(status));
-
- // 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)) {
- errOffset = segment.getOffset();
- 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;
- errOffset = segment.getOffset();
- 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;
- errOffset = segment.getOffset();
- 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_IDENTIFIER_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;
- errOffset = segment.getOffset();
- 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;
- case u'E':
- CHECK_NULL(seen, notation, status);
- blueprint_helpers::parseScientificStem(segment, macros, status);
- return STATE_NULL;
- case u'0':
- CHECK_NULL(seen, integerWidth, status);
- blueprint_helpers::parseIntegerStem(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<StemEnum>(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_PERCENT_100:
- CHECK_NULL(seen, scale, status);
- CHECK_NULL(seen, unit, status);
- macros.scale = Scale::powerOfTen(2);
- macros.unit = NoUnit::percent();
- 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_UNIT:
- CHECK_NULL(seen, unit, status);
- CHECK_NULL(seen, perUnit, status);
- return STATE_IDENTIFIER_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:
- UPRV_UNREACHABLE;
- }
-}
-
-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_IDENTIFIER_UNIT:
- blueprint_helpers::parseIdentifierUnitOption(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;
- }
-
- // Remove the trailing space
- if (sb.length() > 0) {
- sb.truncate(sb.length() - 1);
- }
-}
-
-
-bool blueprint_helpers::parseExponentWidthOption(const StringSegment& segment, MacroProps& macros,
- UErrorCode&) {
- if (!isWildcardChar(segment.charAt(0))) {
- 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<ScientificNotation&>(macros.notation).withMinExponentDigits(minExp);
- return true;
-}
-
-void
-blueprint_helpers::generateExponentWidthOption(int32_t minExponentDigits, UnicodeString& sb, UErrorCode&) {
- sb.append(kWildcardChar);
- 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<StemEnum>(tempStemTrie.getValue()));
- if (sign == UNUM_SIGN_COUNT) {
- return false;
- }
- macros.notation = static_cast<ScientificNotation&>(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: save 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::parseIdentifierUnitOption(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);
-
- ErrorCode internalStatus;
- auto fullUnit = MeasureUnitImpl::forIdentifier(buffer.toStringPiece(), internalStatus);
- if (internalStatus.isFailure()) {
- // throw new SkeletonSyntaxException("Invalid core unit identifier", segment, e);
- status = U_NUMBER_SKELETON_SYNTAX_ERROR;
- return;
- }
-
- // TODO(ICU-20941): Clean this up.
- for (int32_t i = 0; i < fullUnit.units.length(); i++) {
- SingleUnitImpl* subUnit = fullUnit.units[i];
- if (subUnit->dimensionality > 0) {
- macros.unit = macros.unit.product(subUnit->build(status), status);
- } else {
- subUnit->dimensionality *= -1;
- macros.perUnit = macros.perUnit.product(subUnit->build(status), status);
- }
- }
-}
-
-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 (isWildcardChar(segment.charAt(offset))) {
- 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) {
- if (minFrac == 0) {
- macros.precision = Precision::unlimited();
- } else {
- 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(kWildcardChar);
- } else {
- appendMultiple(sb, u'#', maxFrac - minFrac);
- }
-}
-
-void
-blueprint_helpers::parseDigitsStem(const StringSegment& segment, MacroProps& macros, UErrorCode& status) {
- U_ASSERT(segment.charAt(0) == u'@');
- int32_t offset = 0;
- int32_t minSig = 0;
- int32_t maxSig;
- for (; offset < segment.length(); offset++) {
- if (segment.charAt(offset) == u'@') {
- minSig++;
- } else {
- break;
- }
- }
- if (offset < segment.length()) {
- if (isWildcardChar(segment.charAt(offset))) {
- 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(kWildcardChar);
- } else {
- appendMultiple(sb, u'#', maxSig - minSig);
- }
-}
-
-void blueprint_helpers::parseScientificStem(const StringSegment& segment, MacroProps& macros, UErrorCode& status) {
- U_ASSERT(segment.charAt(0) == u'E');
- {
- int32_t offset = 1;
- if (segment.length() == offset) {
- goto fail;
- }
- bool isEngineering = false;
- if (segment.charAt(offset) == u'E') {
- isEngineering = true;
- offset++;
- if (segment.length() == offset) {
- goto fail;
- }
- }
- UNumberSignDisplay signDisplay = UNUM_SIGN_AUTO;
- if (segment.charAt(offset) == u'+') {
- offset++;
- if (segment.length() == offset) {
- goto fail;
- }
- if (segment.charAt(offset) == u'!') {
- signDisplay = UNUM_SIGN_ALWAYS;
- } else if (segment.charAt(offset) == u'?') {
- signDisplay = UNUM_SIGN_EXCEPT_ZERO;
- } else {
- goto fail;
- }
- offset++;
- if (segment.length() == offset) {
- goto fail;
- }
- }
- int32_t minDigits = 0;
- for (; offset < segment.length(); offset++) {
- if (segment.charAt(offset) != u'0') {
- goto fail;
- }
- minDigits++;
- }
- macros.notation = (isEngineering ? Notation::engineering() : Notation::scientific())
- .withExponentSignDisplay(signDisplay)
- .withMinExponentDigits(minDigits);
- return;
- }
- fail: void();
- // throw new SkeletonSyntaxException("Invalid scientific stem", segment);
- status = U_NUMBER_SKELETON_SYNTAX_ERROR;
- return;
-}
-
-void blueprint_helpers::parseIntegerStem(const StringSegment& segment, MacroProps& macros, UErrorCode& status) {
- U_ASSERT(segment.charAt(0) == u'0');
- int32_t offset = 1;
- for (; offset < segment.length(); offset++) {
- if (segment.charAt(offset) != u'0') {
- offset--;
- break;
- }
- }
- if (offset < segment.length()) {
- // throw new SkeletonSyntaxException("Invalid integer stem", segment);
- status = U_NUMBER_SKELETON_SYNTAX_ERROR;
- return;
- }
- macros.integerWidth = IntegerWidth::zeroFillTo(offset);
- return;
-}
-
-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 (isWildcardChar(segment.charAt(offset))) {
- 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<const FractionPrecision&>(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 (isWildcardChar(segment.charAt(0))) {
- maxInt = -1;
- offset++;
- } else {
- maxInt = 0;
- }
- for (; offset < segment.length(); offset++) {
- if (maxInt != -1 && 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(kWildcardChar);
- } 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> 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
- || macros.precision.fType == Precision::RND_INCREMENT_ONE
- || macros.precision.fType == Precision::RND_INCREMENT_FIVE) {
- 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;
-}
-
-
-// Definitions of public API methods (put here for dependency disentanglement)
-
-#if (U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN) && defined(_MSC_VER)
-// Ignore MSVC warning 4661. This is generated for NumberFormatterSettings<>::toSkeleton() as this method
-// is defined elsewhere (in number_skeletons.cpp). The compiler is warning that the explicit template instantiation
-// inside this single translation unit (CPP file) is incomplete, and thus it isn't sure if the template class is
-// fully defined. However, since each translation unit explicitly instantiates all the necessary template classes,
-// they will all be passed to the linker, and the linker will still find and export all the class members.
-#pragma warning(push)
-#pragma warning(disable: 4661)
-#endif
-
-template<typename Derived>
-UnicodeString NumberFormatterSettings<Derived>::toSkeleton(UErrorCode& status) const {
- if (U_FAILURE(status)) {
- return ICU_Utility::makeBogusString();
- }
- 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
-class icu::number::NumberFormatterSettings<icu::number::UnlocalizedNumberFormatter>;
-template
-class icu::number::NumberFormatterSettings<icu::number::LocalizedNumberFormatter>;
-
-UnlocalizedNumberFormatter
-NumberFormatter::forSkeleton(const UnicodeString& skeleton, UErrorCode& status) {
- return skeleton::create(skeleton, nullptr, status);
-}
-
-UnlocalizedNumberFormatter
-NumberFormatter::forSkeleton(const UnicodeString& skeleton, UParseError& perror, UErrorCode& status) {
- return skeleton::create(skeleton, &perror, status);
-}
-
-#if (U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN) && defined(_MSC_VER)
-// Warning 4661.
-#pragma warning(pop)
-#endif
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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"
+#include "string_segment.h"
+#include "unicode/errorcode.h"
+#include "util.h"
+#include "measunit_impl.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"unit", STEM_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; }
+
+ // Section 3 (concise tokens):
+ b.add(u"K", STEM_COMPACT_SHORT, status);
+ b.add(u"KK", STEM_COMPACT_LONG, status);
+ b.add(u"%", STEM_PERCENT, status);
+ b.add(u"%x100", STEM_PERCENT_100, status);
+ b.add(u",_", STEM_GROUP_OFF, status);
+ b.add(u",?", STEM_GROUP_MIN2, status);
+ b.add(u",!", STEM_GROUP_ON_ALIGNED, status);
+ b.add(u"+!", STEM_SIGN_ALWAYS, status);
+ b.add(u"+_", STEM_SIGN_NEVER, status);
+ b.add(u"()", STEM_SIGN_ACCOUNTING, status);
+ b.add(u"()!", STEM_SIGN_ACCOUNTING_ALWAYS, status);
+ b.add(u"+?", STEM_SIGN_EXCEPT_ZERO, status);
+ b.add(u"()?", STEM_SIGN_ACCOUNTING_EXCEPT_ZERO, 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<char16_t*>(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 */ \
+UPRV_BLOCK_MACRO_BEGIN { \
+ if ((seen).field) { \
+ (status) = U_NUMBER_SKELETON_SYNTAX_ERROR; \
+ return STATE_NULL; \
+ } \
+ (seen).field = true; \
+} UPRV_BLOCK_MACRO_END
+
+
+#define SKELETON_UCHAR_TO_CHAR(dest, src, start, end, status) (void)(dest); \
+UPRV_BLOCK_MACRO_BEGIN { \
+ 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; \
+ } \
+} UPRV_BLOCK_MACRO_END
+
+
+} // 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:
+ UPRV_UNREACHABLE;
+ }
+}
+
+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:
+ UPRV_UNREACHABLE;
+ }
+}
+
+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:
+ UPRV_UNREACHABLE;
+ }
+}
+
+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:
+ UPRV_UNREACHABLE;
+ }
+}
+
+UNumberGroupingStrategy 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:
+ UPRV_UNREACHABLE;
+ }
+}
+
+void enum_to_stem_string::groupingStrategy(UNumberGroupingStrategy 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:
+ UPRV_UNREACHABLE;
+ }
+}
+
+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:
+ UPRV_UNREACHABLE;
+ }
+}
+
+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:
+ UPRV_UNREACHABLE;
+ }
+}
+
+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:
+ UPRV_UNREACHABLE;
+ }
+}
+
+
+UnlocalizedNumberFormatter skeleton::create(
+ const UnicodeString& skeletonString, UParseError* perror, UErrorCode& status) {
+
+ // Initialize perror
+ if (perror != nullptr) {
+ perror->line = 0;
+ perror->offset = -1;
+ perror->preContext[0] = 0;
+ perror->postContext[0] = 0;
+ }
+
+ umtx_initOnce(gNumberSkeletonsInitOnce, &initNumberSkeletons, status);
+ if (U_FAILURE(status)) {
+ return {};
+ }
+
+ int32_t errOffset;
+ MacroProps macros = parseSkeleton(skeletonString, errOffset, status);
+ if (U_SUCCESS(status)) {
+ return NumberFormatter::with().macros(macros);
+ }
+
+ if (perror == nullptr) {
+ return {};
+ }
+
+ // Populate the UParseError with the error location
+ perror->offset = errOffset;
+ int32_t contextStart = uprv_max(0, errOffset - U_PARSE_CONTEXT_LEN + 1);
+ int32_t contextEnd = uprv_min(skeletonString.length(), errOffset + U_PARSE_CONTEXT_LEN - 1);
+ skeletonString.extract(contextStart, errOffset - contextStart, perror->preContext, 0);
+ perror->preContext[errOffset - contextStart] = 0;
+ skeletonString.extract(errOffset, contextEnd - errOffset, perror->postContext, 0);
+ perror->postContext[contextEnd - errOffset] = 0;
+ return {};
+}
+
+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, int32_t& errOffset, UErrorCode& status) {
+ U_ASSERT(U_SUCCESS(status));
+
+ // 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)) {
+ errOffset = segment.getOffset();
+ 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;
+ errOffset = segment.getOffset();
+ 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;
+ errOffset = segment.getOffset();
+ 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_IDENTIFIER_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;
+ errOffset = segment.getOffset();
+ 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;
+ case u'E':
+ CHECK_NULL(seen, notation, status);
+ blueprint_helpers::parseScientificStem(segment, macros, status);
+ return STATE_NULL;
+ case u'0':
+ CHECK_NULL(seen, integerWidth, status);
+ blueprint_helpers::parseIntegerStem(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<StemEnum>(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_PERCENT_100:
+ CHECK_NULL(seen, scale, status);
+ CHECK_NULL(seen, unit, status);
+ macros.scale = Scale::powerOfTen(2);
+ macros.unit = NoUnit::percent();
+ 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_UNIT:
+ CHECK_NULL(seen, unit, status);
+ CHECK_NULL(seen, perUnit, status);
+ return STATE_IDENTIFIER_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:
+ UPRV_UNREACHABLE;
+ }
+}
+
+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_IDENTIFIER_UNIT:
+ blueprint_helpers::parseIdentifierUnitOption(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;
+ }
+
+ // Remove the trailing space
+ if (sb.length() > 0) {
+ sb.truncate(sb.length() - 1);
+ }
+}
+
+
+bool blueprint_helpers::parseExponentWidthOption(const StringSegment& segment, MacroProps& macros,
+ UErrorCode&) {
+ if (!isWildcardChar(segment.charAt(0))) {
+ 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<ScientificNotation&>(macros.notation).withMinExponentDigits(minExp);
+ return true;
+}
+
+void
+blueprint_helpers::generateExponentWidthOption(int32_t minExponentDigits, UnicodeString& sb, UErrorCode&) {
+ sb.append(kWildcardChar);
+ 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<StemEnum>(tempStemTrie.getValue()));
+ if (sign == UNUM_SIGN_COUNT) {
+ return false;
+ }
+ macros.notation = static_cast<ScientificNotation&>(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: save 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::parseIdentifierUnitOption(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);
+
+ ErrorCode internalStatus;
+ auto fullUnit = MeasureUnitImpl::forIdentifier(buffer.toStringPiece(), internalStatus);
+ if (internalStatus.isFailure()) {
+ // throw new SkeletonSyntaxException("Invalid core unit identifier", segment, e);
+ status = U_NUMBER_SKELETON_SYNTAX_ERROR;
+ return;
+ }
+
+ // TODO(ICU-20941): Clean this up.
+ for (int32_t i = 0; i < fullUnit.units.length(); i++) {
+ SingleUnitImpl* subUnit = fullUnit.units[i];
+ if (subUnit->dimensionality > 0) {
+ macros.unit = macros.unit.product(subUnit->build(status), status);
+ } else {
+ subUnit->dimensionality *= -1;
+ macros.perUnit = macros.perUnit.product(subUnit->build(status), status);
+ }
+ }
+}
+
+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 (isWildcardChar(segment.charAt(offset))) {
+ 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) {
+ if (minFrac == 0) {
+ macros.precision = Precision::unlimited();
+ } else {
+ 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(kWildcardChar);
+ } else {
+ appendMultiple(sb, u'#', maxFrac - minFrac);
+ }
+}
+
+void
+blueprint_helpers::parseDigitsStem(const StringSegment& segment, MacroProps& macros, UErrorCode& status) {
+ U_ASSERT(segment.charAt(0) == u'@');
+ int32_t offset = 0;
+ int32_t minSig = 0;
+ int32_t maxSig;
+ for (; offset < segment.length(); offset++) {
+ if (segment.charAt(offset) == u'@') {
+ minSig++;
+ } else {
+ break;
+ }
+ }
+ if (offset < segment.length()) {
+ if (isWildcardChar(segment.charAt(offset))) {
+ 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(kWildcardChar);
+ } else {
+ appendMultiple(sb, u'#', maxSig - minSig);
+ }
+}
+
+void blueprint_helpers::parseScientificStem(const StringSegment& segment, MacroProps& macros, UErrorCode& status) {
+ U_ASSERT(segment.charAt(0) == u'E');
+ {
+ int32_t offset = 1;
+ if (segment.length() == offset) {
+ goto fail;
+ }
+ bool isEngineering = false;
+ if (segment.charAt(offset) == u'E') {
+ isEngineering = true;
+ offset++;
+ if (segment.length() == offset) {
+ goto fail;
+ }
+ }
+ UNumberSignDisplay signDisplay = UNUM_SIGN_AUTO;
+ if (segment.charAt(offset) == u'+') {
+ offset++;
+ if (segment.length() == offset) {
+ goto fail;
+ }
+ if (segment.charAt(offset) == u'!') {
+ signDisplay = UNUM_SIGN_ALWAYS;
+ } else if (segment.charAt(offset) == u'?') {
+ signDisplay = UNUM_SIGN_EXCEPT_ZERO;
+ } else {
+ goto fail;
+ }
+ offset++;
+ if (segment.length() == offset) {
+ goto fail;
+ }
+ }
+ int32_t minDigits = 0;
+ for (; offset < segment.length(); offset++) {
+ if (segment.charAt(offset) != u'0') {
+ goto fail;
+ }
+ minDigits++;
+ }
+ macros.notation = (isEngineering ? Notation::engineering() : Notation::scientific())
+ .withExponentSignDisplay(signDisplay)
+ .withMinExponentDigits(minDigits);
+ return;
+ }
+ fail: void();
+ // throw new SkeletonSyntaxException("Invalid scientific stem", segment);
+ status = U_NUMBER_SKELETON_SYNTAX_ERROR;
+ return;
+}
+
+void blueprint_helpers::parseIntegerStem(const StringSegment& segment, MacroProps& macros, UErrorCode& status) {
+ U_ASSERT(segment.charAt(0) == u'0');
+ int32_t offset = 1;
+ for (; offset < segment.length(); offset++) {
+ if (segment.charAt(offset) != u'0') {
+ offset--;
+ break;
+ }
+ }
+ if (offset < segment.length()) {
+ // throw new SkeletonSyntaxException("Invalid integer stem", segment);
+ status = U_NUMBER_SKELETON_SYNTAX_ERROR;
+ return;
+ }
+ macros.integerWidth = IntegerWidth::zeroFillTo(offset);
+ return;
+}
+
+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 (isWildcardChar(segment.charAt(offset))) {
+ 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<const FractionPrecision&>(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 (isWildcardChar(segment.charAt(0))) {
+ maxInt = -1;
+ offset++;
+ } else {
+ maxInt = 0;
+ }
+ for (; offset < segment.length(); offset++) {
+ if (maxInt != -1 && 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(kWildcardChar);
+ } 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> 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
+ || macros.precision.fType == Precision::RND_INCREMENT_ONE
+ || macros.precision.fType == Precision::RND_INCREMENT_FIVE) {
+ 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;
+}
+
+
+// Definitions of public API methods (put here for dependency disentanglement)
+
+#if (U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN) && defined(_MSC_VER)
+// Ignore MSVC warning 4661. This is generated for NumberFormatterSettings<>::toSkeleton() as this method
+// is defined elsewhere (in number_skeletons.cpp). The compiler is warning that the explicit template instantiation
+// inside this single translation unit (CPP file) is incomplete, and thus it isn't sure if the template class is
+// fully defined. However, since each translation unit explicitly instantiates all the necessary template classes,
+// they will all be passed to the linker, and the linker will still find and export all the class members.
+#pragma warning(push)
+#pragma warning(disable: 4661)
+#endif
+
+template<typename Derived>
+UnicodeString NumberFormatterSettings<Derived>::toSkeleton(UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return ICU_Utility::makeBogusString();
+ }
+ 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
+class icu::number::NumberFormatterSettings<icu::number::UnlocalizedNumberFormatter>;
+template
+class icu::number::NumberFormatterSettings<icu::number::LocalizedNumberFormatter>;
+
+UnlocalizedNumberFormatter
+NumberFormatter::forSkeleton(const UnicodeString& skeleton, UErrorCode& status) {
+ return skeleton::create(skeleton, nullptr, status);
+}
+
+UnlocalizedNumberFormatter
+NumberFormatter::forSkeleton(const UnicodeString& skeleton, UParseError& perror, UErrorCode& status) {
+ return skeleton::create(skeleton, &perror, status);
+}
+
+#if (U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN) && defined(_MSC_VER)
+// Warning 4661.
+#pragma warning(pop)
+#endif
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_skeletons.h b/contrib/libs/icu/i18n/number_skeletons.h
index d9b2c0ee0b..4217598561 100644
--- a/contrib/libs/icu/i18n/number_skeletons.h
+++ b/contrib/libs/icu/i18n/number_skeletons.h
@@ -1,352 +1,352 @@
-// © 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"
-#include "string_segment.h"
-
-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_IDENTIFIER_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_PERCENT_100, // concise-only
- 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_UNIT,
- STEM_CURRENCY,
- STEM_INTEGER_WIDTH,
- STEM_NUMBERING_SYSTEM,
- STEM_SCALE,
-};
-
-/** Default wildcard char, accepted on input and printed in output */
-constexpr char16_t kWildcardChar = u'*';
-
-/** Alternative wildcard char, accept on input but not printed in output */
-constexpr char16_t kAltWildcardChar = u'+';
-
-/** Checks whether the char is a wildcard on input */
-inline bool isWildcardChar(char16_t c) {
- return c == kWildcardChar || c == kAltWildcardChar;
-}
-
-/**
- * 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, UParseError* perror, 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, int32_t& errOffset, 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);
-
-UNumberGroupingStrategy 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(UNumberGroupingStrategy 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 parseIdentifierUnitOption(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);
-
-void parseScientificStem(const StringSegment& segment, MacroProps& macros, UErrorCode& status);
-
-// Note: no generateScientificStem since this syntax was added later in ICU 67
-
-void parseIntegerStem(const StringSegment& segment, MacroProps& macros, UErrorCode& status);
-
-// Note: no generateIntegerStem since this syntax was added later in ICU 67
-
-/** @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 */
+// © 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"
+#include "string_segment.h"
+
+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_IDENTIFIER_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_PERCENT_100, // concise-only
+ 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_UNIT,
+ STEM_CURRENCY,
+ STEM_INTEGER_WIDTH,
+ STEM_NUMBERING_SYSTEM,
+ STEM_SCALE,
+};
+
+/** Default wildcard char, accepted on input and printed in output */
+constexpr char16_t kWildcardChar = u'*';
+
+/** Alternative wildcard char, accept on input but not printed in output */
+constexpr char16_t kAltWildcardChar = u'+';
+
+/** Checks whether the char is a wildcard on input */
+inline bool isWildcardChar(char16_t c) {
+ return c == kWildcardChar || c == kAltWildcardChar;
+}
+
+/**
+ * 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, UParseError* perror, 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, int32_t& errOffset, 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);
+
+UNumberGroupingStrategy 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(UNumberGroupingStrategy 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 parseIdentifierUnitOption(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);
+
+void parseScientificStem(const StringSegment& segment, MacroProps& macros, UErrorCode& status);
+
+// Note: no generateScientificStem since this syntax was added later in ICU 67
+
+void parseIntegerStem(const StringSegment& segment, MacroProps& macros, UErrorCode& status);
+
+// Note: no generateIntegerStem since this syntax was added later in ICU 67
+
+/** @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/contrib/libs/icu/i18n/number_types.h b/contrib/libs/icu/i18n/number_types.h
index 5c2b8cf8b5..fe109538a3 100644
--- a/contrib/libs/icu/i18n/number_types.h
+++ b/contrib/libs/icu/i18n/number_types.h
@@ -1,366 +1,366 @@
-// © 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_TYPES_H__
-#define __NUMBER_TYPES_H__
-
-#include <cstdint>
-#include "unicode/decimfmt.h"
-#include "unicode/unum.h"
-#include "unicode/numsys.h"
-#include "unicode/numberformatter.h"
-#include "unicode/utf16.h"
-#include "uassert.h"
-#include "unicode/platform.h"
-#include "unicode/uniset.h"
-#include "standardplural.h"
-#include "formatted_string_builder.h"
-
-U_NAMESPACE_BEGIN
-namespace number {
-namespace impl {
-
-// For convenience and historical reasons, import the Field typedef to the namespace.
-typedef FormattedStringBuilder::Field Field;
-
-// Typedef several enums for brevity and for easier comparison to Java.
-
-typedef UNumberFormatRoundingMode RoundingMode;
-
-typedef UNumberFormatPadPosition PadPosition;
-
-typedef UNumberCompactStyle CompactStyle;
-
-// ICU4J Equivalent: RoundingUtils.MAX_INT_FRAC_SIG
-static constexpr int32_t kMaxIntFracSig = 999;
-
-// ICU4J Equivalent: RoundingUtils.DEFAULT_ROUNDING_MODE
-static constexpr RoundingMode kDefaultMode = RoundingMode::UNUM_FOUND_HALFEVEN;
-
-// ICU4J Equivalent: Padder.FALLBACK_PADDING_STRING
-static constexpr char16_t kFallbackPaddingString[] = u" ";
-
-// Forward declarations:
-
-class Modifier;
-class MutablePatternModifier;
-class DecimalQuantity;
-class ModifierStore;
-struct MicroProps;
-
-
-enum AffixPatternType {
- // Represents a literal character; the value is stored in the code point field.
- TYPE_CODEPOINT = 0,
-
- // Represents a minus sign symbol '-'.
- TYPE_MINUS_SIGN = -1,
-
- // Represents a plus sign symbol '+'.
- TYPE_PLUS_SIGN = -2,
-
- // Represents a percent sign symbol '%'.
- TYPE_PERCENT = -3,
-
- // Represents a permille sign symbol '‰'.
- TYPE_PERMILLE = -4,
-
- // Represents a single currency symbol '¤'.
- TYPE_CURRENCY_SINGLE = -5,
-
- // Represents a double currency symbol '¤¤'.
- TYPE_CURRENCY_DOUBLE = -6,
-
- // Represents a triple currency symbol '¤¤¤'.
- TYPE_CURRENCY_TRIPLE = -7,
-
- // Represents a quadruple currency symbol '¤¤¤¤'.
- TYPE_CURRENCY_QUAD = -8,
-
- // Represents a quintuple currency symbol '¤¤¤¤¤'.
- TYPE_CURRENCY_QUINT = -9,
-
- // Represents a sequence of six or more currency symbols.
- TYPE_CURRENCY_OVERFLOW = -15
-};
-
-enum CompactType {
- TYPE_DECIMAL, TYPE_CURRENCY
-};
-
-enum Signum {
- SIGNUM_NEG = 0,
- SIGNUM_NEG_ZERO = 1,
- SIGNUM_POS_ZERO = 2,
- SIGNUM_POS = 3,
- SIGNUM_COUNT = 4,
-};
-
-
-class U_I18N_API AffixPatternProvider {
- public:
- static const int32_t AFFIX_PLURAL_MASK = 0xff;
- static const int32_t AFFIX_PREFIX = 0x100;
- static const int32_t AFFIX_NEGATIVE_SUBPATTERN = 0x200;
- static const int32_t AFFIX_PADDING = 0x400;
-
- // 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;
-
- virtual bool hasNegativeSubpattern() const = 0;
-
- virtual bool negativeHasMinusSign() 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
- * have one. This is used in cases like compact notation, where the pattern replaces the entire
- * number instead of rendering the number.
- */
- virtual bool hasBody() const = 0;
-};
-
-
-/**
- * A Modifier is an object that can be passed through the formatting pipeline until it is finally applied to the string
- * builder. A Modifier usually contains a prefix and a suffix that are applied, but it could contain something else,
- * like a {@link com.ibm.icu.text.SimpleFormatter} pattern.
- *
- * A Modifier is usually immutable, except in cases such as {@link MutablePatternModifier}, which are mutable for performance
- * reasons.
- *
- * Exported as U_I18N_API because it is a base class for other exported types
- */
-class U_I18N_API Modifier {
- public:
- virtual ~Modifier();
-
- /**
- * Apply this Modifier to the string builder.
- *
- * @param output
- * The string builder to which to apply this modifier.
- * @param leftIndex
- * The left index of the string within the builder. Equal to 0 when only one number is being formatted.
- * @param rightIndex
- * The right index of the string within the string builder. Equal to length when only one number is being
- * formatted.
- * @return The number of characters (UTF-16 code units) that were added to the string builder.
- */
- virtual int32_t apply(FormattedStringBuilder& 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
- * prefix and suffix strings.
- *
- * @return The number of characters (UTF-16 code units) in the prefix.
- */
- virtual int32_t getPrefixLength() const = 0;
-
- /**
- * Returns the number of code points in the modifier, prefix plus suffix.
- */
- virtual int32_t getCodePointCount() const = 0;
-
- /**
- * Whether this modifier is strong. If a modifier is strong, it should always be applied immediately and not allowed
- * to bubble up. With regard to padding, strong modifiers are considered to be on the inside of the prefix and
- * suffix.
- *
- * @return Whether the modifier is strong.
- */
- virtual bool isStrong() const = 0;
-
- /**
- * Whether the modifier contains at least one occurrence of the given field.
- */
- virtual bool containsField(Field field) const = 0;
-
- /**
- * A fill-in for getParameters(). obj will always be set; if non-null, the other
- * two fields are also safe to read.
- */
- struct U_I18N_API Parameters {
- const ModifierStore* obj = nullptr;
- Signum signum;
- StandardPlural::Form plural;
-
- Parameters();
- Parameters(const ModifierStore* _obj, Signum _signum, StandardPlural::Form _plural);
- };
-
- /**
- * Gets a set of "parameters" for this Modifier.
- *
- * TODO: Make this return a `const Parameters*` more like Java?
- */
- virtual void getParameters(Parameters& output) const = 0;
-
- /**
- * Returns whether this Modifier is *semantically equivalent* to the other Modifier;
- * in many cases, this is the same as equal, but parameters should be ignored.
- */
- virtual bool semanticallyEquivalent(const Modifier& other) const = 0;
-};
-
-
-/**
- * This is *not* a modifier; rather, it is an object that can return modifiers
- * based on given parameters.
- *
- * Exported as U_I18N_API because it is a base class for other exported types.
- */
-class U_I18N_API ModifierStore {
- public:
- virtual ~ModifierStore();
-
- /**
- * Returns a Modifier with the given parameters (best-effort).
- */
- virtual const Modifier* getModifier(Signum signum, StandardPlural::Form plural) const = 0;
-};
-
-
-/**
- * This interface is used when all number formatting settings, including the locale, are known, except for the quantity
- * itself. The {@link #processQuantity} method performs the final step in the number processing pipeline: it uses the
- * quantity to generate a finalized {@link MicroProps}, which can be used to render the number to output.
- *
- * <p>
- * In other words, this interface is used for the parts of number processing that are <em>quantity-dependent</em>.
- *
- * <p>
- * In order to allow for multiple different objects to all mutate the same MicroProps, a "chain" of MicroPropsGenerators
- * are linked together, and each one is responsible for manipulating a certain quantity-dependent part of the
- * MicroProps. At the tail of the linked list is a base instance of {@link MicroProps} with properties that are not
- * quantity-dependent. Each element in the linked list calls {@link #processQuantity} on its "parent", then does its
- * work, and then returns the result.
- *
- * Exported as U_I18N_API because it is a base class for other exported types
- *
- */
-class U_I18N_API MicroPropsGenerator {
- public:
- virtual ~MicroPropsGenerator();
-
- /**
- * Considers the given {@link DecimalQuantity}, optionally mutates it, and returns a {@link MicroProps}.
- *
- * @param quantity
- * The quantity for consideration and optional mutation.
- * @param micros
- * The MicroProps instance to populate.
- * @return A MicroProps instance resolved for the quantity.
- */
- virtual void processQuantity(DecimalQuantity& quantity, MicroProps& micros,
- UErrorCode& status) const = 0;
-};
-
-/**
- * An interface used by compact notation and scientific notation to choose a multiplier while rounding.
- */
-class MultiplierProducer {
- public:
- virtual ~MultiplierProducer();
-
- /**
- * Maps a magnitude to a multiplier in powers of ten. For example, in compact notation in English, a magnitude of 5
- * (e.g., 100,000) should return a multiplier of -3, since the number is displayed in thousands.
- *
- * @param magnitude
- * The power of ten of the input number.
- * @return The shift in powers of ten.
- */
- virtual int32_t getMultiplier(int32_t magnitude) const = 0;
-};
-
-// Exported as U_I18N_API because it is a public member field of exported DecimalFormatProperties
-template<typename T>
-class U_I18N_API NullableValue {
- public:
- NullableValue()
- : fNull(true) {}
-
- NullableValue(const NullableValue<T>& other) = default;
-
- explicit NullableValue(const T& other) {
- fValue = other;
- fNull = false;
- }
-
- NullableValue<T>& operator=(const NullableValue<T>& other) {
- fNull = other.fNull;
- if (!fNull) {
- fValue = other.fValue;
- }
- return *this;
- }
-
- NullableValue<T>& operator=(const T& other) {
- fValue = other;
- fNull = false;
- return *this;
- }
-
- 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<bool>(fValue == other.fValue));
- }
-
- void nullify() {
- // TODO: It might be nice to call the destructor here.
- fNull = true;
- }
-
- bool isNull() const {
- return fNull;
- }
-
- 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;
-};
-
-
-} // namespace impl
-} // namespace number
-U_NAMESPACE_END
-
-#endif //__NUMBER_TYPES_H__
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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_TYPES_H__
+#define __NUMBER_TYPES_H__
+
+#include <cstdint>
+#include "unicode/decimfmt.h"
+#include "unicode/unum.h"
+#include "unicode/numsys.h"
+#include "unicode/numberformatter.h"
+#include "unicode/utf16.h"
+#include "uassert.h"
+#include "unicode/platform.h"
+#include "unicode/uniset.h"
+#include "standardplural.h"
+#include "formatted_string_builder.h"
+
+U_NAMESPACE_BEGIN
+namespace number {
+namespace impl {
+
+// For convenience and historical reasons, import the Field typedef to the namespace.
+typedef FormattedStringBuilder::Field Field;
+
+// Typedef several enums for brevity and for easier comparison to Java.
+
+typedef UNumberFormatRoundingMode RoundingMode;
+
+typedef UNumberFormatPadPosition PadPosition;
+
+typedef UNumberCompactStyle CompactStyle;
+
+// ICU4J Equivalent: RoundingUtils.MAX_INT_FRAC_SIG
+static constexpr int32_t kMaxIntFracSig = 999;
+
+// ICU4J Equivalent: RoundingUtils.DEFAULT_ROUNDING_MODE
+static constexpr RoundingMode kDefaultMode = RoundingMode::UNUM_FOUND_HALFEVEN;
+
+// ICU4J Equivalent: Padder.FALLBACK_PADDING_STRING
+static constexpr char16_t kFallbackPaddingString[] = u" ";
+
+// Forward declarations:
+
+class Modifier;
+class MutablePatternModifier;
+class DecimalQuantity;
+class ModifierStore;
+struct MicroProps;
+
+
+enum AffixPatternType {
+ // Represents a literal character; the value is stored in the code point field.
+ TYPE_CODEPOINT = 0,
+
+ // Represents a minus sign symbol '-'.
+ TYPE_MINUS_SIGN = -1,
+
+ // Represents a plus sign symbol '+'.
+ TYPE_PLUS_SIGN = -2,
+
+ // Represents a percent sign symbol '%'.
+ TYPE_PERCENT = -3,
+
+ // Represents a permille sign symbol '‰'.
+ TYPE_PERMILLE = -4,
+
+ // Represents a single currency symbol '¤'.
+ TYPE_CURRENCY_SINGLE = -5,
+
+ // Represents a double currency symbol '¤¤'.
+ TYPE_CURRENCY_DOUBLE = -6,
+
+ // Represents a triple currency symbol '¤¤¤'.
+ TYPE_CURRENCY_TRIPLE = -7,
+
+ // Represents a quadruple currency symbol '¤¤¤¤'.
+ TYPE_CURRENCY_QUAD = -8,
+
+ // Represents a quintuple currency symbol '¤¤¤¤¤'.
+ TYPE_CURRENCY_QUINT = -9,
+
+ // Represents a sequence of six or more currency symbols.
+ TYPE_CURRENCY_OVERFLOW = -15
+};
+
+enum CompactType {
+ TYPE_DECIMAL, TYPE_CURRENCY
+};
+
+enum Signum {
+ SIGNUM_NEG = 0,
+ SIGNUM_NEG_ZERO = 1,
+ SIGNUM_POS_ZERO = 2,
+ SIGNUM_POS = 3,
+ SIGNUM_COUNT = 4,
+};
+
+
+class U_I18N_API AffixPatternProvider {
+ public:
+ static const int32_t AFFIX_PLURAL_MASK = 0xff;
+ static const int32_t AFFIX_PREFIX = 0x100;
+ static const int32_t AFFIX_NEGATIVE_SUBPATTERN = 0x200;
+ static const int32_t AFFIX_PADDING = 0x400;
+
+ // 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;
+
+ virtual bool hasNegativeSubpattern() const = 0;
+
+ virtual bool negativeHasMinusSign() 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
+ * have one. This is used in cases like compact notation, where the pattern replaces the entire
+ * number instead of rendering the number.
+ */
+ virtual bool hasBody() const = 0;
+};
+
+
+/**
+ * A Modifier is an object that can be passed through the formatting pipeline until it is finally applied to the string
+ * builder. A Modifier usually contains a prefix and a suffix that are applied, but it could contain something else,
+ * like a {@link com.ibm.icu.text.SimpleFormatter} pattern.
+ *
+ * A Modifier is usually immutable, except in cases such as {@link MutablePatternModifier}, which are mutable for performance
+ * reasons.
+ *
+ * Exported as U_I18N_API because it is a base class for other exported types
+ */
+class U_I18N_API Modifier {
+ public:
+ virtual ~Modifier();
+
+ /**
+ * Apply this Modifier to the string builder.
+ *
+ * @param output
+ * The string builder to which to apply this modifier.
+ * @param leftIndex
+ * The left index of the string within the builder. Equal to 0 when only one number is being formatted.
+ * @param rightIndex
+ * The right index of the string within the string builder. Equal to length when only one number is being
+ * formatted.
+ * @return The number of characters (UTF-16 code units) that were added to the string builder.
+ */
+ virtual int32_t apply(FormattedStringBuilder& 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
+ * prefix and suffix strings.
+ *
+ * @return The number of characters (UTF-16 code units) in the prefix.
+ */
+ virtual int32_t getPrefixLength() const = 0;
+
+ /**
+ * Returns the number of code points in the modifier, prefix plus suffix.
+ */
+ virtual int32_t getCodePointCount() const = 0;
+
+ /**
+ * Whether this modifier is strong. If a modifier is strong, it should always be applied immediately and not allowed
+ * to bubble up. With regard to padding, strong modifiers are considered to be on the inside of the prefix and
+ * suffix.
+ *
+ * @return Whether the modifier is strong.
+ */
+ virtual bool isStrong() const = 0;
+
+ /**
+ * Whether the modifier contains at least one occurrence of the given field.
+ */
+ virtual bool containsField(Field field) const = 0;
+
+ /**
+ * A fill-in for getParameters(). obj will always be set; if non-null, the other
+ * two fields are also safe to read.
+ */
+ struct U_I18N_API Parameters {
+ const ModifierStore* obj = nullptr;
+ Signum signum;
+ StandardPlural::Form plural;
+
+ Parameters();
+ Parameters(const ModifierStore* _obj, Signum _signum, StandardPlural::Form _plural);
+ };
+
+ /**
+ * Gets a set of "parameters" for this Modifier.
+ *
+ * TODO: Make this return a `const Parameters*` more like Java?
+ */
+ virtual void getParameters(Parameters& output) const = 0;
+
+ /**
+ * Returns whether this Modifier is *semantically equivalent* to the other Modifier;
+ * in many cases, this is the same as equal, but parameters should be ignored.
+ */
+ virtual bool semanticallyEquivalent(const Modifier& other) const = 0;
+};
+
+
+/**
+ * This is *not* a modifier; rather, it is an object that can return modifiers
+ * based on given parameters.
+ *
+ * Exported as U_I18N_API because it is a base class for other exported types.
+ */
+class U_I18N_API ModifierStore {
+ public:
+ virtual ~ModifierStore();
+
+ /**
+ * Returns a Modifier with the given parameters (best-effort).
+ */
+ virtual const Modifier* getModifier(Signum signum, StandardPlural::Form plural) const = 0;
+};
+
+
+/**
+ * This interface is used when all number formatting settings, including the locale, are known, except for the quantity
+ * itself. The {@link #processQuantity} method performs the final step in the number processing pipeline: it uses the
+ * quantity to generate a finalized {@link MicroProps}, which can be used to render the number to output.
+ *
+ * <p>
+ * In other words, this interface is used for the parts of number processing that are <em>quantity-dependent</em>.
+ *
+ * <p>
+ * In order to allow for multiple different objects to all mutate the same MicroProps, a "chain" of MicroPropsGenerators
+ * are linked together, and each one is responsible for manipulating a certain quantity-dependent part of the
+ * MicroProps. At the tail of the linked list is a base instance of {@link MicroProps} with properties that are not
+ * quantity-dependent. Each element in the linked list calls {@link #processQuantity} on its "parent", then does its
+ * work, and then returns the result.
+ *
+ * Exported as U_I18N_API because it is a base class for other exported types
+ *
+ */
+class U_I18N_API MicroPropsGenerator {
+ public:
+ virtual ~MicroPropsGenerator();
+
+ /**
+ * Considers the given {@link DecimalQuantity}, optionally mutates it, and returns a {@link MicroProps}.
+ *
+ * @param quantity
+ * The quantity for consideration and optional mutation.
+ * @param micros
+ * The MicroProps instance to populate.
+ * @return A MicroProps instance resolved for the quantity.
+ */
+ virtual void processQuantity(DecimalQuantity& quantity, MicroProps& micros,
+ UErrorCode& status) const = 0;
+};
+
+/**
+ * An interface used by compact notation and scientific notation to choose a multiplier while rounding.
+ */
+class MultiplierProducer {
+ public:
+ virtual ~MultiplierProducer();
+
+ /**
+ * Maps a magnitude to a multiplier in powers of ten. For example, in compact notation in English, a magnitude of 5
+ * (e.g., 100,000) should return a multiplier of -3, since the number is displayed in thousands.
+ *
+ * @param magnitude
+ * The power of ten of the input number.
+ * @return The shift in powers of ten.
+ */
+ virtual int32_t getMultiplier(int32_t magnitude) const = 0;
+};
+
+// Exported as U_I18N_API because it is a public member field of exported DecimalFormatProperties
+template<typename T>
+class U_I18N_API NullableValue {
+ public:
+ NullableValue()
+ : fNull(true) {}
+
+ NullableValue(const NullableValue<T>& other) = default;
+
+ explicit NullableValue(const T& other) {
+ fValue = other;
+ fNull = false;
+ }
+
+ NullableValue<T>& operator=(const NullableValue<T>& other) {
+ fNull = other.fNull;
+ if (!fNull) {
+ fValue = other.fValue;
+ }
+ return *this;
+ }
+
+ NullableValue<T>& operator=(const T& other) {
+ fValue = other;
+ fNull = false;
+ return *this;
+ }
+
+ 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<bool>(fValue == other.fValue));
+ }
+
+ void nullify() {
+ // TODO: It might be nice to call the destructor here.
+ fNull = true;
+ }
+
+ bool isNull() const {
+ return fNull;
+ }
+
+ 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;
+};
+
+
+} // namespace impl
+} // namespace number
+U_NAMESPACE_END
+
+#endif //__NUMBER_TYPES_H__
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_utils.cpp b/contrib/libs/icu/i18n/number_utils.cpp
index 91d7f335cd..326e646232 100644
--- a/contrib/libs/icu/i18n/number_utils.cpp
+++ b/contrib/libs/icu/i18n/number_utils.cpp
@@ -1,266 +1,266 @@
-// © 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 <stdlib.h>
-#include <cmath>
-#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
- UPRV_UNREACHABLE;
- }
- 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<int32_t>(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<uint8_t>(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<uint8_t>(isNegative ? DECNEG : 0);
- uprv_decNumberSetBCD(fData, bcd, static_cast<uint32_t>(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 & DEC_Inexact) != 0) {
- // Ignore.
- } else 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());
-}
-
-void DecNum::toString(ByteSink& output, UErrorCode& status) const {
- if (U_FAILURE(status)) {
- return;
- }
- // "string must be at least dn->digits+14 characters long"
- int32_t minCapacity = fData.getAlias()->digits + 14;
- MaybeStackArray<char, 30> buffer(minCapacity);
- uprv_decNumberToString(fData, buffer.getAlias());
- output.Append(buffer.getAlias(), static_cast<int32_t>(uprv_strlen(buffer.getAlias())));
-}
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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 <stdlib.h>
+#include <cmath>
+#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
+ UPRV_UNREACHABLE;
+ }
+ 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<int32_t>(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<uint8_t>(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<uint8_t>(isNegative ? DECNEG : 0);
+ uprv_decNumberSetBCD(fData, bcd, static_cast<uint32_t>(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 & DEC_Inexact) != 0) {
+ // Ignore.
+ } else 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());
+}
+
+void DecNum::toString(ByteSink& output, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ // "string must be at least dn->digits+14 characters long"
+ int32_t minCapacity = fData.getAlias()->digits + 14;
+ MaybeStackArray<char, 30> buffer(minCapacity);
+ uprv_decNumberToString(fData, buffer.getAlias());
+ output.Append(buffer.getAlias(), static_cast<int32_t>(uprv_strlen(buffer.getAlias())));
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_utils.h b/contrib/libs/icu/i18n/number_utils.h
index 93195f080b..4f302df86d 100644
--- a/contrib/libs/icu/i18n/number_utils.h
+++ b/contrib/libs/icu/i18n/number_utils.h
@@ -1,112 +1,112 @@
-// © 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_UTILS_H__
-#define __NUMBER_UTILS_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"
-#include "formatted_string_builder.h"
-
-U_NAMESPACE_BEGIN
-
-namespace number {
-namespace impl {
-
-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,
-};
-
-// Namespace for naked functions
-namespace utils {
-
-inline int32_t insertDigitFromSymbols(FormattedStringBuilder& 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);
-}
-
-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;
-}
-
-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;
-}
-
-// NOTE: In Java, this method is in NumberFormat.java
-const char16_t*
-getPatternForStyle(const Locale& locale, const char* nsName, CldrPatternStyle style, UErrorCode& status);
-
-/**
- * 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.
- */
-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 {
- UnicodeString ruleString = rules->select(fdec);
- return StandardPlural::orOtherFromString(ruleString);
- }
-}
-
-/**
- * Computes the plural form after copying the number and applying rounding rules.
- */
-inline StandardPlural::Form getPluralSafe(
- const RoundingImpl& rounder,
- const PluralRules* rules,
- const DecimalQuantity& dq,
- UErrorCode& status) {
- // TODO(ICU-20500): Avoid the copy?
- DecimalQuantity copy(dq);
- rounder.apply(copy, status);
- if (U_FAILURE(status)) {
- return StandardPlural::Form::OTHER;
- }
- return getStandardPlural(rules, copy);
-}
-
-} // namespace utils
-
-} // namespace impl
-} // namespace number
-
-U_NAMESPACE_END
-
-#endif //__NUMBER_UTILS_H__
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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_UTILS_H__
+#define __NUMBER_UTILS_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"
+#include "formatted_string_builder.h"
+
+U_NAMESPACE_BEGIN
+
+namespace number {
+namespace impl {
+
+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,
+};
+
+// Namespace for naked functions
+namespace utils {
+
+inline int32_t insertDigitFromSymbols(FormattedStringBuilder& 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);
+}
+
+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;
+}
+
+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;
+}
+
+// NOTE: In Java, this method is in NumberFormat.java
+const char16_t*
+getPatternForStyle(const Locale& locale, const char* nsName, CldrPatternStyle style, UErrorCode& status);
+
+/**
+ * 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.
+ */
+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 {
+ UnicodeString ruleString = rules->select(fdec);
+ return StandardPlural::orOtherFromString(ruleString);
+ }
+}
+
+/**
+ * Computes the plural form after copying the number and applying rounding rules.
+ */
+inline StandardPlural::Form getPluralSafe(
+ const RoundingImpl& rounder,
+ const PluralRules* rules,
+ const DecimalQuantity& dq,
+ UErrorCode& status) {
+ // TODO(ICU-20500): Avoid the copy?
+ DecimalQuantity copy(dq);
+ rounder.apply(copy, status);
+ if (U_FAILURE(status)) {
+ return StandardPlural::Form::OTHER;
+ }
+ return getStandardPlural(rules, copy);
+}
+
+} // namespace utils
+
+} // namespace impl
+} // namespace number
+
+U_NAMESPACE_END
+
+#endif //__NUMBER_UTILS_H__
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/number_utypes.h b/contrib/libs/icu/i18n/number_utypes.h
index 7a1b7a4e80..b1adb14c54 100644
--- a/contrib/libs/icu/i18n/number_utypes.h
+++ b/contrib/libs/icu/i18n/number_utypes.h
@@ -1,50 +1,50 @@
-// © 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 "formatted_string_builder.h"
-#include "formattedval_impl.h"
-
-U_NAMESPACE_BEGIN namespace number {
-namespace impl {
-
-
-/** Helper function used in upluralrules.cpp */
-const DecimalQuantity* validateUFormattedNumberToDecimalQuantity(
- const UFormattedNumber* uresult, UErrorCode& status);
-
-
-/**
- * Struct for data used by FormattedNumber.
- *
- * This struct is 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.
- *
- * Exported as U_I18N_API for tests
- */
-class U_I18N_API UFormattedNumberData : public FormattedValueStringBuilderImpl {
-public:
- UFormattedNumberData() : FormattedValueStringBuilderImpl(kUndefinedField) {}
- virtual ~UFormattedNumberData();
-
- DecimalQuantity quantity;
-};
-
-
-} // namespace impl
-} // namespace number
-U_NAMESPACE_END
-
-#endif //__SOURCE_NUMBER_UTYPES_H__
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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 "formatted_string_builder.h"
+#include "formattedval_impl.h"
+
+U_NAMESPACE_BEGIN namespace number {
+namespace impl {
+
+
+/** Helper function used in upluralrules.cpp */
+const DecimalQuantity* validateUFormattedNumberToDecimalQuantity(
+ const UFormattedNumber* uresult, UErrorCode& status);
+
+
+/**
+ * Struct for data used by FormattedNumber.
+ *
+ * This struct is 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.
+ *
+ * Exported as U_I18N_API for tests
+ */
+class U_I18N_API UFormattedNumberData : public FormattedValueStringBuilderImpl {
+public:
+ UFormattedNumberData() : FormattedValueStringBuilderImpl(kUndefinedField) {}
+ virtual ~UFormattedNumberData();
+
+ DecimalQuantity quantity;
+};
+
+
+} // namespace impl
+} // namespace number
+U_NAMESPACE_END
+
+#endif //__SOURCE_NUMBER_UTYPES_H__
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/numfmt.cpp b/contrib/libs/icu/i18n/numfmt.cpp
index 7c3a0551c3..64b7812d67 100644
--- a/contrib/libs/icu/i18n/numfmt.cpp
+++ b/contrib/libs/icu/i18n/numfmt.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -54,8 +54,8 @@
#include <float.h>
#include "sharednumberformat.h"
#include "unifiedcache.h"
-#include "number_decimalquantity.h"
-#include "number_utils.h"
+#include "number_decimalquantity.h"
+#include "number_utils.h"
//#define FMT_DEBUG
@@ -130,28 +130,28 @@ static const UChar * const gLastResortNumberPatterns[UNUM_FORMAT_STYLE_COUNT] =
// Keys used for accessing resource bundles
-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
+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.
- 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
+ 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
@@ -521,17 +521,17 @@ ArgExtractor::ArgExtractor(const NumberFormat& /*nf*/, const Formattable& obj, U
ArgExtractor::~ArgExtractor() {
}
-UnicodeString& NumberFormat::format(const number::impl::DecimalQuantity &number,
+UnicodeString& NumberFormat::format(const number::impl::DecimalQuantity &number,
UnicodeString& appendTo,
FieldPositionIterator* posIter,
UErrorCode& status) const {
// DecimalFormat overrides this function, and handles DigitList based big decimals.
- // Other subclasses (ChoiceFormat) do not (yet) handle DigitLists,
+ // Other subclasses (ChoiceFormat) do not (yet) handle DigitLists,
// so this default implementation falls back to formatting decimal numbers as doubles.
if (U_FAILURE(status)) {
return appendTo;
}
- double dnum = number.toDouble();
+ double dnum = number.toDouble();
format(dnum, appendTo, posIter, status);
return appendTo;
}
@@ -539,17 +539,17 @@ UnicodeString& NumberFormat::format(const number::impl::DecimalQuantity &number,
UnicodeString&
-NumberFormat::format(const number::impl::DecimalQuantity &number,
+NumberFormat::format(const number::impl::DecimalQuantity &number,
UnicodeString& appendTo,
FieldPosition& pos,
- UErrorCode &status) const {
+ UErrorCode &status) const {
// DecimalFormat overrides this function, and handles DigitList based big decimals.
- // Other subclasses (ChoiceFormat) do not (yet) handle DigitLists,
+ // Other subclasses (ChoiceFormat) do not (yet) handle DigitLists,
// so this default implementation falls back to formatting decimal numbers as doubles.
if (U_FAILURE(status)) {
return appendTo;
}
- double dnum = number.toDouble();
+ double dnum = number.toDouble();
format(dnum, appendTo, pos, status);
return appendTo;
}
@@ -569,13 +569,13 @@ NumberFormat::format(const Formattable& obj,
if(arg.wasCurrency() && u_strcmp(iso, getCurrency())) {
// trying to format a different currency.
// Right now, we clone.
- LocalPointer<NumberFormat> cloneFmt(this->clone());
+ LocalPointer<NumberFormat> cloneFmt(this->clone());
cloneFmt->setCurrency(iso, status);
// next line should NOT recurse, because n is numeric whereas obj was a wrapper around currency amount.
return cloneFmt->format(*n, appendTo, pos, status);
}
- if (n->isNumeric() && n->getDecimalQuantity() != 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.
//
@@ -584,17 +584,17 @@ NumberFormat::format(const Formattable& obj,
// know about DigitList to continue to operate as they had.
//
// DecimalFormat overrides the DigitList formatting functions.
- format(*n->getDecimalQuantity(), appendTo, pos, status);
+ format(*n->getDecimalQuantity(), appendTo, pos, status);
} else {
switch (n->getType()) {
case Formattable::kDouble:
- format(n->getDouble(), appendTo, pos, status);
+ format(n->getDouble(), appendTo, pos, status);
break;
case Formattable::kLong:
- format(n->getLong(), appendTo, pos, status);
+ format(n->getLong(), appendTo, pos, status);
break;
case Formattable::kInt64:
- format(n->getInt64(), appendTo, pos, status);
+ format(n->getInt64(), appendTo, pos, status);
break;
default:
status = U_INVALID_FORMAT_ERROR;
@@ -624,15 +624,15 @@ NumberFormat::format(const Formattable& obj,
if(arg.wasCurrency() && u_strcmp(iso, getCurrency())) {
// trying to format a different currency.
// Right now, we clone.
- LocalPointer<NumberFormat> cloneFmt(this->clone());
+ LocalPointer<NumberFormat> cloneFmt(this->clone());
cloneFmt->setCurrency(iso, status);
// next line should NOT recurse, because n is numeric whereas obj was a wrapper around currency amount.
return cloneFmt->format(*n, appendTo, posIter, status);
}
- if (n->isNumeric() && n->getDecimalQuantity() != NULL) {
+ if (n->isNumeric() && n->getDecimalQuantity() != NULL) {
// Decimal Number
- format(*n->getDecimalQuantity(), appendTo, posIter, status);
+ format(*n->getDecimalQuantity(), appendTo, posIter, status);
} else {
switch (n->getType()) {
case Formattable::kDouble:
@@ -986,19 +986,19 @@ static UBool haveService() {
URegistryKey U_EXPORT2
NumberFormat::registerFactory(NumberFormatFactory* toAdopt, UErrorCode& status)
{
- if (U_FAILURE(status)) {
- delete toAdopt;
- return nullptr;
- }
- ICULocaleService *service = getNumberFormatService();
- if (service) {
- NFFactory *tempnnf = new NFFactory(toAdopt);
- if (tempnnf != NULL) {
- return service->registerFactory(tempnnf, status);
- }
- }
- status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
+ if (U_FAILURE(status)) {
+ delete toAdopt;
+ return nullptr;
+ }
+ ICULocaleService *service = getNumberFormatService();
+ if (service) {
+ NFFactory *tempnnf = new NFFactory(toAdopt);
+ if (tempnnf != NULL) {
+ return service->registerFactory(tempnnf, status);
+ }
+ }
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
}
// -------------------------------------
@@ -1059,7 +1059,7 @@ NumberFormat::createInstance(const Locale& loc, UNumberFormatStyle kind, UErrorC
if (U_FAILURE(status)) {
return NULL;
}
- NumberFormat *result = (*shared)->clone();
+ NumberFormat *result = (*shared)->clone();
shared->removeRef();
if (result == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
@@ -1189,7 +1189,7 @@ void NumberFormat::setCurrency(const UChar* theCurrency, UErrorCode& ec) {
}
}
-const char16_t* NumberFormat::getCurrency() const {
+const char16_t* NumberFormat::getCurrency() const {
return fCurrency;
}
@@ -1335,7 +1335,7 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
case UNUM_DECIMAL:
curr = FALSE;
// fall-through
- U_FALLTHROUGH;
+ U_FALLTHROUGH;
case UNUM_CURRENCY:
case UNUM_CURRENCY_ISO: // do not support plural formatting here
@@ -1343,13 +1343,13 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
case UNUM_CURRENCY_ACCOUNTING:
case UNUM_CASH_CURRENCY:
case UNUM_CURRENCY_STANDARD:
- {
- LocalPointer<Win32NumberFormat> f(new Win32NumberFormat(desiredLocale, curr, status), status);
+ {
+ LocalPointer<Win32NumberFormat> f(new Win32NumberFormat(desiredLocale, curr, status), status);
if (U_SUCCESS(status)) {
- return f.orphan();
+ return f.orphan();
}
- }
- break;
+ }
+ break;
default:
break;
}
@@ -1366,7 +1366,7 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
// TODO: Bad hash key usage, see ticket #8504.
int32_t hashKey = desiredLocale.hashCode();
- static UMutex nscacheMutex;
+ static UMutex nscacheMutex;
Mutex lock(&nscacheMutex);
ns = (NumberingSystem *)uhash_iget(NumberingSystem_cache, hashKey);
if (ns == NULL) {
@@ -1401,13 +1401,13 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
return NULL;
}
- // 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);
+ // 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;
@@ -1420,7 +1420,7 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
}
}
- LocalPointer<NumberFormat> f;
+ LocalPointer<NumberFormat> f;
if (ns->isAlgorithmic()) {
UnicodeString nsDesc;
UnicodeString nsRuleSetGroup;
@@ -1455,7 +1455,7 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
return NULL;
}
r->setDefaultRuleSet(nsRuleSetName,status);
- f.adoptInstead(r);
+ f.adoptInstead(r);
} else {
// replace single currency sign in the pattern with double currency sign
// if the style is UNUM_CURRENCY_ISO
@@ -1464,33 +1464,33 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
UnicodeString(TRUE, gDoubleCurrencySign, 2));
}
- // "new DecimalFormat()" does not adopt the symbols argument if its memory allocation fails.
- // So we can't use adoptInsteadAndCheckErrorCode as we need to know if the 'new' failed.
- DecimalFormatSymbols *syms = symbolsToAdopt.getAlias();
- LocalPointer<DecimalFormat> df(new DecimalFormat(pattern, syms, style, status));
-
- if (df.isValid()) {
- // if the DecimalFormat object was successfully new'ed, then it will own symbolsToAdopt, even if the status is a failure.
- symbolsToAdopt.orphan();
- }
- else {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
-
- if (U_FAILURE(status)) {
- return nullptr;
- }
-
+ // "new DecimalFormat()" does not adopt the symbols argument if its memory allocation fails.
+ // So we can't use adoptInsteadAndCheckErrorCode as we need to know if the 'new' failed.
+ DecimalFormatSymbols *syms = symbolsToAdopt.getAlias();
+ LocalPointer<DecimalFormat> df(new DecimalFormat(pattern, syms, style, status));
+
+ if (df.isValid()) {
+ // if the DecimalFormat object was successfully new'ed, then it will own symbolsToAdopt, even if the status is a failure.
+ symbolsToAdopt.orphan();
+ }
+ else {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+
// if it is cash currency style, setCurrencyUsage with usage
if (style == UNUM_CASH_CURRENCY){
df->setCurrencyUsage(UCURR_USAGE_CASH, &status);
}
if (U_FAILURE(status)) {
- return nullptr;
+ return nullptr;
}
- f.adoptInstead(df.orphan());
+ f.adoptInstead(df.orphan());
}
f->setLocaleIDs(ures_getLocaleByType(ownedResource.getAlias(), ULOC_VALID_LOCALE, &status),
@@ -1498,27 +1498,27 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
if (U_FAILURE(status)) {
return NULL;
}
- return f.orphan();
-}
-
-/**
- * Get the rounding mode.
- * @return A rounding mode
- */
-NumberFormat::ERoundingMode NumberFormat::getRoundingMode() const {
- // Default value. ICU4J throws an exception and we can't change this API.
- return NumberFormat::ERoundingMode::kRoundUnnecessary;
-}
-
-/**
- * Set the rounding mode. This has no effect unless the rounding
- * increment is greater than zero.
- * @param roundingMode A rounding mode
- */
-void NumberFormat::setRoundingMode(NumberFormat::ERoundingMode /*roundingMode*/) {
- // No-op ICU4J throws an exception, and we can't change this API.
-}
-
+ return f.orphan();
+}
+
+/**
+ * Get the rounding mode.
+ * @return A rounding mode
+ */
+NumberFormat::ERoundingMode NumberFormat::getRoundingMode() const {
+ // Default value. ICU4J throws an exception and we can't change this API.
+ return NumberFormat::ERoundingMode::kRoundUnnecessary;
+}
+
+/**
+ * Set the rounding mode. This has no effect unless the rounding
+ * increment is greater than zero.
+ * @param roundingMode A rounding mode
+ */
+void NumberFormat::setRoundingMode(NumberFormat::ERoundingMode /*roundingMode*/) {
+ // No-op ICU4J throws an exception, and we can't change this API.
+}
+
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/numparse_affixes.cpp b/contrib/libs/icu/i18n/numparse_affixes.cpp
index ca293e741d..82b989e487 100644
--- a/contrib/libs/icu/i18n/numparse_affixes.cpp
+++ b/contrib/libs/icu/i18n/numparse_affixes.cpp
@@ -1,473 +1,473 @@
-// © 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"
-#include "string_segment.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:
- UPRV_UNREACHABLE;
- }
-
- } 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.
- if (auto* ptr = fWarehouse.nextCodePointMatcher(cp, status)) {
- addMatcher(*ptr);
- } else {
- // OOM; unwind the stack
- return;
- }
- }
- 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);
-}
-
-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, UErrorCode& status) {
- if (U_FAILURE(status)) {
- return nullptr;
- }
- auto* result = fCodePoints.create(cp);
- if (result == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
- return result;
-}
-
-
-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"<CodePoint>";
-}
-
-
-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);
-
- 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 typeInt = 0; typeInt < PATTERN_SIGN_TYPE_COUNT; typeInt++) {
- auto type = static_cast<PatternSignType>(typeInt);
-
- // Skip affixes in some cases
- if (type == PATTERN_SIGN_TYPE_POS
- && 0 != (parseFlags & PARSE_FLAG_PLUS_SIGN_ALLOWED)) {
- continue;
- }
- if (type == PATTERN_SIGN_TYPE_POS_SIGN
- && 0 == (parseFlags & PARSE_FLAG_PLUS_SIGN_ALLOWED)) {
- continue;
- }
-
- // Generate Prefix
- bool hasPrefix = false;
- PatternStringUtils::patternInfoToStringBuilder(
- patternInfo, true, type, 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, type, StandardPlural::OTHER, false, sb);
- fAffixPatternMatchers[numAffixPatternMatchers] = AffixPatternMatcher::fromAffixPattern(
- sb, *fTokenWarehouse, parseFlags, &hasSuffix, status);
- AffixPatternMatcher* suffix = hasSuffix ? &fAffixPatternMatchers[numAffixPatternMatchers++]
- : nullptr;
-
- if (type == PATTERN_SIGN_TYPE_POS) {
- 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 = (type == PATTERN_SIGN_TYPE_NEG) ? 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 (type == PATTERN_SIGN_TYPE_POS || !equals(prefix, posPrefix)) {
- fAffixMatchers[numAffixMatchers++] = {prefix, nullptr, flags};
- }
- if (type == PATTERN_SIGN_TYPE_POS || !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"<Affix") + (isNegative ? u":negative " : u" ") +
- (fPrefix ? fPrefix->getPattern() : u"null") + u"#" +
- (fSuffix ? fSuffix->getPattern() : u"null") + u">";
-
-}
-
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+// © 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"
+#include "string_segment.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:
+ UPRV_UNREACHABLE;
+ }
+
+ } 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.
+ if (auto* ptr = fWarehouse.nextCodePointMatcher(cp, status)) {
+ addMatcher(*ptr);
+ } else {
+ // OOM; unwind the stack
+ return;
+ }
+ }
+ 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);
+}
+
+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, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ auto* result = fCodePoints.create(cp);
+ if (result == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return result;
+}
+
+
+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"<CodePoint>";
+}
+
+
+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);
+
+ 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 typeInt = 0; typeInt < PATTERN_SIGN_TYPE_COUNT; typeInt++) {
+ auto type = static_cast<PatternSignType>(typeInt);
+
+ // Skip affixes in some cases
+ if (type == PATTERN_SIGN_TYPE_POS
+ && 0 != (parseFlags & PARSE_FLAG_PLUS_SIGN_ALLOWED)) {
+ continue;
+ }
+ if (type == PATTERN_SIGN_TYPE_POS_SIGN
+ && 0 == (parseFlags & PARSE_FLAG_PLUS_SIGN_ALLOWED)) {
+ continue;
+ }
+
+ // Generate Prefix
+ bool hasPrefix = false;
+ PatternStringUtils::patternInfoToStringBuilder(
+ patternInfo, true, type, 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, type, StandardPlural::OTHER, false, sb);
+ fAffixPatternMatchers[numAffixPatternMatchers] = AffixPatternMatcher::fromAffixPattern(
+ sb, *fTokenWarehouse, parseFlags, &hasSuffix, status);
+ AffixPatternMatcher* suffix = hasSuffix ? &fAffixPatternMatchers[numAffixPatternMatchers++]
+ : nullptr;
+
+ if (type == PATTERN_SIGN_TYPE_POS) {
+ 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 = (type == PATTERN_SIGN_TYPE_NEG) ? 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 (type == PATTERN_SIGN_TYPE_POS || !equals(prefix, posPrefix)) {
+ fAffixMatchers[numAffixMatchers++] = {prefix, nullptr, flags};
+ }
+ if (type == PATTERN_SIGN_TYPE_POS || !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"<Affix") + (isNegative ? u":negative " : u" ") +
+ (fPrefix ? fPrefix->getPattern() : u"null") + u"#" +
+ (fSuffix ? fSuffix->getPattern() : u"null") + u">";
+
+}
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/contrib/libs/icu/i18n/numparse_affixes.h b/contrib/libs/icu/i18n/numparse_affixes.h
index 97a17f4d78..d18ed08833 100644
--- a/contrib/libs/icu/i18n/numparse_affixes.h
+++ b/contrib/libs/icu/i18n/numparse_affixes.h
@@ -1,225 +1,225 @@
-// © 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 "cmemory.h"
-
-#include "numparse_types.h"
-#include "numparse_symbols.h"
-#include "numparse_currency.h"
-#include "number_affixutils.h"
-#include "number_currencysymbols.h"
-
-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 U_I18N_API 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, MemoryPool 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 numparse::impl 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<numparse::impl::CodePointMatcher*, 8>;
-template class U_I18N_API MaybeStackArray<UChar, 4>;
-template class U_I18N_API MemoryPool<numparse::impl::CodePointMatcher, 8>;
-template class U_I18N_API numparse::impl::CompactUnicodeString<4>;
-#endif
-
-namespace numparse {
-namespace impl {
-
-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, UErrorCode& status);
-
- 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.
- MemoryPool<CodePointMatcher> 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 */
+// © 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 "cmemory.h"
+
+#include "numparse_types.h"
+#include "numparse_symbols.h"
+#include "numparse_currency.h"
+#include "number_affixutils.h"
+#include "number_currencysymbols.h"
+
+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 U_I18N_API 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, MemoryPool 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 numparse::impl 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<numparse::impl::CodePointMatcher*, 8>;
+template class U_I18N_API MaybeStackArray<UChar, 4>;
+template class U_I18N_API MemoryPool<numparse::impl::CodePointMatcher, 8>;
+template class U_I18N_API numparse::impl::CompactUnicodeString<4>;
+#endif
+
+namespace numparse {
+namespace impl {
+
+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, UErrorCode& status);
+
+ 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.
+ MemoryPool<CodePointMatcher> 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/contrib/libs/icu/i18n/numparse_compositions.cpp b/contrib/libs/icu/i18n/numparse_compositions.cpp
index 2f7e1ab28d..f343b5a043 100644
--- a/contrib/libs/icu/i18n/numparse_compositions.cpp
+++ b/contrib/libs/icu/i18n/numparse_compositions.cpp
@@ -1,108 +1,108 @@
-// © 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 "string_segment.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"<ArraySeries>";
-}
-
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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 "string_segment.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"<ArraySeries>";
+}
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/numparse_compositions.h b/contrib/libs/icu/i18n/numparse_compositions.h
index f085912def..9ed7f474eb 100644
--- a/contrib/libs/icu/i18n/numparse_compositions.h
+++ b/contrib/libs/icu/i18n/numparse_compositions.h
@@ -1,124 +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<const numparse::impl::NumberParseMatcher*, 3>;
-#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<const NumberParseMatcher*, 3> 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 */
+// © 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<const numparse::impl::NumberParseMatcher*, 3>;
+#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<const NumberParseMatcher*, 3> 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/contrib/libs/icu/i18n/numparse_currency.cpp b/contrib/libs/icu/i18n/numparse_currency.cpp
index 6b53a73edf..1fc8154cfb 100644
--- a/contrib/libs/icu/i18n/numparse_currency.cpp
+++ b/contrib/libs/icu/i18n/numparse_currency.cpp
@@ -1,189 +1,189 @@
-// © 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"
-#include "string_segment.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<StandardPlural::COUNT; i++) {
- auto plural = static_cast<StandardPlural::Form>(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()) {
- // ISO codes should be accepted case-insensitive.
- // https://unicode-org.atlassian.net/browse/ICU-13696
- overlap2 = segment.getCommonPrefixLength(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<StandardPlural::COUNT; i++) {
- const UnicodeString& name = fLocalLongNames[i];
- int32_t overlap = segment.getCommonPrefixLength(name);
- if (overlap == name.length() && name.length() > 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"<CombinedCurrencyMatcher>";
-}
-
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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"
+#include "string_segment.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<StandardPlural::COUNT; i++) {
+ auto plural = static_cast<StandardPlural::Form>(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()) {
+ // ISO codes should be accepted case-insensitive.
+ // https://unicode-org.atlassian.net/browse/ICU-13696
+ overlap2 = segment.getCommonPrefixLength(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<StandardPlural::COUNT; i++) {
+ const UnicodeString& name = fLocalLongNames[i];
+ int32_t overlap = segment.getCommonPrefixLength(name);
+ if (overlap == name.length() && name.length() > 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"<CombinedCurrencyMatcher>";
+}
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/numparse_currency.h b/contrib/libs/icu/i18n/numparse_currency.h
index a94943312f..812c6b4b04 100644
--- a/contrib/libs/icu/i18n/numparse_currency.h
+++ b/contrib/libs/icu/i18n/numparse_currency.h
@@ -1,74 +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 */
+// © 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/contrib/libs/icu/i18n/numparse_decimal.cpp b/contrib/libs/icu/i18n/numparse_decimal.cpp
index cf1e815672..813512c06b 100644
--- a/contrib/libs/icu/i18n/numparse_decimal.cpp
+++ b/contrib/libs/icu/i18n/numparse_decimal.cpp
@@ -1,459 +1,459 @@
-// © 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"
-#include "string_segment.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<int8_t>(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<int8_t>(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<int32_t>(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"<Decimal>";
-}
-
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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"
+#include "string_segment.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<int8_t>(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<int8_t>(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<int32_t>(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"<Decimal>";
+}
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/numparse_decimal.h b/contrib/libs/icu/i18n/numparse_decimal.h
index ec6c76487e..6bb6c4be1a 100644
--- a/contrib/libs/icu/i18n/numparse_decimal.h
+++ b/contrib/libs/icu/i18n/numparse_decimal.h
@@ -1,76 +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<const UnicodeSet> fLocalDecimalUniSet;
- LocalPointer<const UnicodeSet> fLocalSeparatorSet;
- LocalArray<const UnicodeString> 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 */
+// © 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<const UnicodeSet> fLocalDecimalUniSet;
+ LocalPointer<const UnicodeSet> fLocalSeparatorSet;
+ LocalArray<const UnicodeString> 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/contrib/libs/icu/i18n/numparse_impl.cpp b/contrib/libs/icu/i18n/numparse_impl.cpp
index 4b76da1c14..cb50a0858d 100644
--- a/contrib/libs/icu/i18n/numparse_impl.cpp
+++ b/contrib/libs/icu/i18n/numparse_impl.cpp
@@ -1,365 +1,365 @@
-// © 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 <typeinfo>
-#include <array>
-#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<NumberParserImpl> parser(new NumberParserImpl(parseFlags));
- DecimalFormatSymbols symbols(locale, status);
-
- parser->fLocalMatchers.ignorables = {parseFlags};
- 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(parser->fLocalValidators.number = {});
-
- parser->freeze();
- return parser.orphan();
-}
-
-NumberParserImpl*
-NumberParserImpl::createParserFromProperties(const number::impl::DecimalFormatProperties& properties,
- const DecimalFormatSymbols& symbols, bool parseCurrency,
- UErrorCode& status) {
- Locale locale = symbols.getLocale();
- AutoAffixPatternProvider affixProvider(properties, status);
- if (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 (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;
- parseFlags |= PARSE_FLAG_STRICT_IGNORABLES;
- } else {
- parseFlags |= PARSE_FLAG_INCLUDE_UNPAIRED_AFFIXES;
- }
- if (grouper.getPrimary() <= 0) {
- parseFlags |= PARSE_FLAG_GROUPING_DISABLED;
- }
- if (parseCurrency || affixProvider.get().hasCurrencySign()) {
- parseFlags |= PARSE_FLAG_MONETARY_SEPARATORS;
- }
- if (!parseCurrency) {
- parseFlags |= PARSE_FLAG_NO_FOREIGN_CURRENCY;
- }
-
- LocalPointer<NumberParserImpl> parser(new NumberParserImpl(parseFlags));
-
- parser->fLocalMatchers.ignorables = {parseFlags};
- 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.get(), *parser, ignorables, parseFlags, status);
-
- ////////////////////////
- /// CURRENCY MATCHER ///
- ////////////////////////
-
- if (parseCurrency || affixProvider.get().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 (!isStrict && affixProvider.get().containsSymbolType(AffixPatternType::TYPE_PERCENT, status)) {
- parser->addMatcher(parser->fLocalMatchers.percent = {symbols});
- }
- if (!isStrict && affixProvider.get().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) {
- parseGreedy(segment, result, status);
- } else if (0 != (fParseFlags & PARSE_FLAG_ALLOW_INFINITE_RECURSION)) {
- // Start at 1 so that recursionLevels never gets to 0
- parseLongestRecursive(segment, result, 1, status);
- } else {
- // Arbitrary recursion safety limit: 100 levels.
- parseLongestRecursive(segment, result, -100, status);
- }
- for (int32_t i = 0; i < fNumMatchers; i++) {
- fMatchers[i]->postProcess(result);
- }
- result.postProcess();
-}
-
-void NumberParserImpl::parseGreedy(StringSegment& segment, ParsedNumber& result,
- UErrorCode& status) const {
- // Note: this method is not recursive in order to avoid stack overflow.
- for (int i = 0; i <fNumMatchers;) {
- // Base Case
- if (segment.length() == 0) {
- return;
- }
- const NumberParseMatcher* matcher = fMatchers[i];
- if (!matcher->smokeTest(segment)) {
- // Matcher failed smoke test: try the next one
- i++;
- continue;
- }
- int32_t initialOffset = segment.getOffset();
- matcher->match(segment, result, status);
- if (U_FAILURE(status)) {
- return;
- }
- if (segment.getOffset() != initialOffset) {
- // Greedy heuristic: accept the match and loop back
- i = 0;
- continue;
- } else {
- // Matcher did not match: try the next one
- i++;
- continue;
- }
- UPRV_UNREACHABLE;
- }
-
- // NOTE: If we get here, the greedy parse completed without consuming the entire string.
-}
-
-void NumberParserImpl::parseLongestRecursive(StringSegment& segment, ParsedNumber& result,
- int32_t recursionLevels,
- UErrorCode& status) const {
- // Base Case
- if (segment.length() == 0) {
- return;
- }
-
- // Safety against stack overflow
- if (recursionLevels == 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, recursionLevels + 1, 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"<NumberParserImpl matchers:[");
- for (int32_t i = 0; i < fNumMatchers; i++) {
- result.append(u' ');
- result.append(fMatchers[i]->toString());
- }
- result.append(u" ]>", -1);
- return result;
-}
-
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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 <typeinfo>
+#include <array>
+#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<NumberParserImpl> parser(new NumberParserImpl(parseFlags));
+ DecimalFormatSymbols symbols(locale, status);
+
+ parser->fLocalMatchers.ignorables = {parseFlags};
+ 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(parser->fLocalValidators.number = {});
+
+ parser->freeze();
+ return parser.orphan();
+}
+
+NumberParserImpl*
+NumberParserImpl::createParserFromProperties(const number::impl::DecimalFormatProperties& properties,
+ const DecimalFormatSymbols& symbols, bool parseCurrency,
+ UErrorCode& status) {
+ Locale locale = symbols.getLocale();
+ AutoAffixPatternProvider affixProvider(properties, status);
+ if (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 (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;
+ parseFlags |= PARSE_FLAG_STRICT_IGNORABLES;
+ } else {
+ parseFlags |= PARSE_FLAG_INCLUDE_UNPAIRED_AFFIXES;
+ }
+ if (grouper.getPrimary() <= 0) {
+ parseFlags |= PARSE_FLAG_GROUPING_DISABLED;
+ }
+ if (parseCurrency || affixProvider.get().hasCurrencySign()) {
+ parseFlags |= PARSE_FLAG_MONETARY_SEPARATORS;
+ }
+ if (!parseCurrency) {
+ parseFlags |= PARSE_FLAG_NO_FOREIGN_CURRENCY;
+ }
+
+ LocalPointer<NumberParserImpl> parser(new NumberParserImpl(parseFlags));
+
+ parser->fLocalMatchers.ignorables = {parseFlags};
+ 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.get(), *parser, ignorables, parseFlags, status);
+
+ ////////////////////////
+ /// CURRENCY MATCHER ///
+ ////////////////////////
+
+ if (parseCurrency || affixProvider.get().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 (!isStrict && affixProvider.get().containsSymbolType(AffixPatternType::TYPE_PERCENT, status)) {
+ parser->addMatcher(parser->fLocalMatchers.percent = {symbols});
+ }
+ if (!isStrict && affixProvider.get().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) {
+ parseGreedy(segment, result, status);
+ } else if (0 != (fParseFlags & PARSE_FLAG_ALLOW_INFINITE_RECURSION)) {
+ // Start at 1 so that recursionLevels never gets to 0
+ parseLongestRecursive(segment, result, 1, status);
+ } else {
+ // Arbitrary recursion safety limit: 100 levels.
+ parseLongestRecursive(segment, result, -100, status);
+ }
+ for (int32_t i = 0; i < fNumMatchers; i++) {
+ fMatchers[i]->postProcess(result);
+ }
+ result.postProcess();
+}
+
+void NumberParserImpl::parseGreedy(StringSegment& segment, ParsedNumber& result,
+ UErrorCode& status) const {
+ // Note: this method is not recursive in order to avoid stack overflow.
+ for (int i = 0; i <fNumMatchers;) {
+ // Base Case
+ if (segment.length() == 0) {
+ return;
+ }
+ const NumberParseMatcher* matcher = fMatchers[i];
+ if (!matcher->smokeTest(segment)) {
+ // Matcher failed smoke test: try the next one
+ i++;
+ continue;
+ }
+ int32_t initialOffset = segment.getOffset();
+ matcher->match(segment, result, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (segment.getOffset() != initialOffset) {
+ // Greedy heuristic: accept the match and loop back
+ i = 0;
+ continue;
+ } else {
+ // Matcher did not match: try the next one
+ i++;
+ continue;
+ }
+ UPRV_UNREACHABLE;
+ }
+
+ // NOTE: If we get here, the greedy parse completed without consuming the entire string.
+}
+
+void NumberParserImpl::parseLongestRecursive(StringSegment& segment, ParsedNumber& result,
+ int32_t recursionLevels,
+ UErrorCode& status) const {
+ // Base Case
+ if (segment.length() == 0) {
+ return;
+ }
+
+ // Safety against stack overflow
+ if (recursionLevels == 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, recursionLevels + 1, 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"<NumberParserImpl matchers:[");
+ for (int32_t i = 0; i < fNumMatchers; i++) {
+ result.append(u' ');
+ result.append(fMatchers[i]->toString());
+ }
+ result.append(u" ]>", -1);
+ return result;
+}
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/numparse_impl.h b/contrib/libs/icu/i18n/numparse_impl.h
index 380d9aa4c6..ec1969e68c 100644
--- a/contrib/libs/icu/i18n/numparse_impl.h
+++ b/contrib/libs/icu/i18n/numparse_impl.h
@@ -1,111 +1,111 @@
-// © 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"
-#include "string_segment.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<const numparse::impl::NumberParseMatcher*, 10>;
-#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<const NumberParseMatcher*, 10> 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 parseGreedy(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const;
-
- void parseLongestRecursive(
- StringSegment& segment, ParsedNumber& result, int32_t recursionLevels, UErrorCode& status) const;
-};
-
-
-} // namespace impl
-} // namespace numparse
-U_NAMESPACE_END
-
-#endif //__NUMPARSE_IMPL_H__
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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"
+#include "string_segment.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<const numparse::impl::NumberParseMatcher*, 10>;
+#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<const NumberParseMatcher*, 10> 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 parseGreedy(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const;
+
+ void parseLongestRecursive(
+ StringSegment& segment, ParsedNumber& result, int32_t recursionLevels, UErrorCode& status) const;
+};
+
+
+} // namespace impl
+} // namespace numparse
+U_NAMESPACE_END
+
+#endif //__NUMPARSE_IMPL_H__
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/numparse_parsednumber.cpp b/contrib/libs/icu/i18n/numparse_parsednumber.cpp
index 4b373a3c31..cd2dad8883 100644
--- a/contrib/libs/icu/i18n/numparse_parsednumber.cpp
+++ b/contrib/libs/icu/i18n/numparse_parsednumber.cpp
@@ -1,126 +1,126 @@
-// © 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 "string_segment.h"
-#include "putilimp.h"
-#include <cmath>
-
-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(UErrorCode& status) 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;
- }
- }
- if (quantity.bogus) {
- status = U_INVALID_STATE_ERROR;
- return 0.0;
- }
- if (quantity.isZeroish() && quantity.isNegative()) {
- return -0.0;
- }
-
- if (quantity.fitsInLong()) {
- return static_cast<double>(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.isZeroish() && 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 */
+// © 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 "string_segment.h"
+#include "putilimp.h"
+#include <cmath>
+
+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(UErrorCode& status) 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;
+ }
+ }
+ if (quantity.bogus) {
+ status = U_INVALID_STATE_ERROR;
+ return 0.0;
+ }
+ if (quantity.isZeroish() && quantity.isNegative()) {
+ return -0.0;
+ }
+
+ if (quantity.fitsInLong()) {
+ return static_cast<double>(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.isZeroish() && 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/contrib/libs/icu/i18n/numparse_scientific.cpp b/contrib/libs/icu/i18n/numparse_scientific.cpp
index 4b88cd998f..f8c8a3fc75 100644
--- a/contrib/libs/icu/i18n/numparse_scientific.cpp
+++ b/contrib/libs/icu/i18n/numparse_scientific.cpp
@@ -1,163 +1,163 @@
-// © 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"
-#include "string_segment.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),
- fIgnorablesMatcher(PARSE_FLAG_STRICT_IGNORABLES) {
-
- 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;
- }
-
- // Only accept one exponent per string.
- if (0 != (result.flags & FLAG_HAS_EXPONENT)) {
- 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.
- int32_t initialOffset = segment.getOffset();
- int32_t overlap = segment.getCommonPrefixLength(fExponentSeparatorString);
- if (overlap == fExponentSeparatorString.length()) {
- // Full exponent separator match.
-
- // First attempt to get a code point, returning true if we can't get one.
- if (segment.length() == overlap) {
- return true;
- }
- segment.adjustOffset(overlap);
-
- // Allow ignorables before the sign.
- // Note: call site is guarded by the segment.length() check above.
- // Note: the ignorables matcher should not touch the result.
- fIgnorablesMatcher.match(segment, result, status);
- if (segment.length() == 0) {
- segment.setOffset(initialOffset);
- return true;
- }
-
- // 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)) {
- overlap = segment.getCommonPrefixLength(fCustomMinusSign);
- if (overlap != fCustomMinusSign.length()) {
- // Partial custom sign match
- segment.setOffset(initialOffset);
- return true;
- }
- exponentSign = -1;
- segment.adjustOffset(overlap);
- } else if (segment.startsWith(fCustomPlusSign)) {
- overlap = segment.getCommonPrefixLength(fCustomPlusSign);
- if (overlap != fCustomPlusSign.length()) {
- // Partial custom sign match
- segment.setOffset(initialOffset);
- return true;
- }
- segment.adjustOffset(overlap);
- }
-
- // Return true if the segment is empty.
- if (segment.length() == 0) {
- segment.setOffset(initialOffset);
- return true;
- }
-
- // Allow ignorables after the sign.
- // Note: call site is guarded by the segment.length() check above.
- // Note: the ignorables matcher should not touch the result.
- fIgnorablesMatcher.match(segment, result, status);
- if (segment.length() == 0) {
- segment.setOffset(initialOffset);
- return true;
- }
-
- // 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
- segment.setOffset(initialOffset);
- }
- return digitsReturnValue;
-
- } else if (overlap == 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"<Scientific>";
-}
-
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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"
+#include "string_segment.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),
+ fIgnorablesMatcher(PARSE_FLAG_STRICT_IGNORABLES) {
+
+ 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;
+ }
+
+ // Only accept one exponent per string.
+ if (0 != (result.flags & FLAG_HAS_EXPONENT)) {
+ 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.
+ int32_t initialOffset = segment.getOffset();
+ int32_t overlap = segment.getCommonPrefixLength(fExponentSeparatorString);
+ if (overlap == fExponentSeparatorString.length()) {
+ // Full exponent separator match.
+
+ // First attempt to get a code point, returning true if we can't get one.
+ if (segment.length() == overlap) {
+ return true;
+ }
+ segment.adjustOffset(overlap);
+
+ // Allow ignorables before the sign.
+ // Note: call site is guarded by the segment.length() check above.
+ // Note: the ignorables matcher should not touch the result.
+ fIgnorablesMatcher.match(segment, result, status);
+ if (segment.length() == 0) {
+ segment.setOffset(initialOffset);
+ return true;
+ }
+
+ // 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)) {
+ overlap = segment.getCommonPrefixLength(fCustomMinusSign);
+ if (overlap != fCustomMinusSign.length()) {
+ // Partial custom sign match
+ segment.setOffset(initialOffset);
+ return true;
+ }
+ exponentSign = -1;
+ segment.adjustOffset(overlap);
+ } else if (segment.startsWith(fCustomPlusSign)) {
+ overlap = segment.getCommonPrefixLength(fCustomPlusSign);
+ if (overlap != fCustomPlusSign.length()) {
+ // Partial custom sign match
+ segment.setOffset(initialOffset);
+ return true;
+ }
+ segment.adjustOffset(overlap);
+ }
+
+ // Return true if the segment is empty.
+ if (segment.length() == 0) {
+ segment.setOffset(initialOffset);
+ return true;
+ }
+
+ // Allow ignorables after the sign.
+ // Note: call site is guarded by the segment.length() check above.
+ // Note: the ignorables matcher should not touch the result.
+ fIgnorablesMatcher.match(segment, result, status);
+ if (segment.length() == 0) {
+ segment.setOffset(initialOffset);
+ return true;
+ }
+
+ // 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
+ segment.setOffset(initialOffset);
+ }
+ return digitsReturnValue;
+
+ } else if (overlap == 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"<Scientific>";
+}
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/numparse_scientific.h b/contrib/libs/icu/i18n/numparse_scientific.h
index 5617c0c6a6..d513109121 100644
--- a/contrib/libs/icu/i18n/numparse_scientific.h
+++ b/contrib/libs/icu/i18n/numparse_scientific.h
@@ -1,47 +1,47 @@
-// © 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 "numparse_symbols.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;
- IgnorablesMatcher fIgnorablesMatcher;
- UnicodeString fCustomMinusSign;
- UnicodeString fCustomPlusSign;
-};
-
-
-} // namespace impl
-} // namespace numparse
-U_NAMESPACE_END
-
-#endif //__NUMPARSE_SCIENTIFIC_H__
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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 "numparse_symbols.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;
+ IgnorablesMatcher fIgnorablesMatcher;
+ UnicodeString fCustomMinusSign;
+ UnicodeString fCustomPlusSign;
+};
+
+
+} // namespace impl
+} // namespace numparse
+U_NAMESPACE_END
+
+#endif //__NUMPARSE_SCIENTIFIC_H__
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/numparse_symbols.cpp b/contrib/libs/icu/i18n/numparse_symbols.cpp
index 608f4f5c8b..d7c629ef58 100644
--- a/contrib/libs/icu/i18n/numparse_symbols.cpp
+++ b/contrib/libs/icu/i18n/numparse_symbols.cpp
@@ -1,198 +1,198 @@
-// © 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"
-#include "string_segment.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"<Symbol>";
-}
-
-
-IgnorablesMatcher::IgnorablesMatcher(parse_flags_t parseFlags) :
- SymbolMatcher(
- {},
- (0 != (parseFlags & PARSE_FLAG_STRICT_IGNORABLES)) ?
- unisets::STRICT_IGNORABLES :
- unisets::DEFAULT_IGNORABLES) {
-}
-
-bool IgnorablesMatcher::isFlexible() const {
- return true;
-}
-
-UnicodeString IgnorablesMatcher::toString() const {
- return u"<Ignorables>";
-}
-
-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_SIGN) {
-}
-
-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 */
+// © 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"
+#include "string_segment.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"<Symbol>";
+}
+
+
+IgnorablesMatcher::IgnorablesMatcher(parse_flags_t parseFlags) :
+ SymbolMatcher(
+ {},
+ (0 != (parseFlags & PARSE_FLAG_STRICT_IGNORABLES)) ?
+ unisets::STRICT_IGNORABLES :
+ unisets::DEFAULT_IGNORABLES) {
+}
+
+bool IgnorablesMatcher::isFlexible() const {
+ return true;
+}
+
+UnicodeString IgnorablesMatcher::toString() const {
+ return u"<Ignorables>";
+}
+
+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_SIGN) {
+}
+
+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/contrib/libs/icu/i18n/numparse_symbols.h b/contrib/libs/icu/i18n/numparse_symbols.h
index beb133f7d0..fb8dee1046 100644
--- a/contrib/libs/icu/i18n/numparse_symbols.h
+++ b/contrib/libs/icu/i18n/numparse_symbols.h
@@ -1,173 +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(parse_flags_t parseFlags);
-
- 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 */
+// © 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(parse_flags_t parseFlags);
+
+ 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/contrib/libs/icu/i18n/numparse_types.h b/contrib/libs/icu/i18n/numparse_types.h
index b4007c2ff5..7f3db031af 100644
--- a/contrib/libs/icu/i18n/numparse_types.h
+++ b/contrib/libs/icu/i18n/numparse_types.h
@@ -1,271 +1,271 @@
-// © 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"
-#include "string_segment.h"
-
-U_NAMESPACE_BEGIN
-namespace numparse {
-namespace impl {
-
-// Forward-declarations
-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,
- PARSE_FLAG_ALLOW_INFINITE_RECURSION = 0x4000,
- PARSE_FLAG_STRICT_IGNORABLES = 0x8000,
-};
-
-
-// TODO: Is this class worthwhile?
-template<int32_t stackCapacity>
-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) {
- uprv_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<UChar, stackCapacity> 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.
- *
- * <p>
- * <strong>What is a strong versus weak char?</strong> 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(UErrorCode& status) const;
-
- void populateFormattable(Formattable& output, parse_flags_t parseFlags) const;
-
- bool isBetterThan(const ParsedNumber& other);
-};
-
-
-/**
- * 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 */
+// © 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"
+#include "string_segment.h"
+
+U_NAMESPACE_BEGIN
+namespace numparse {
+namespace impl {
+
+// Forward-declarations
+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,
+ PARSE_FLAG_ALLOW_INFINITE_RECURSION = 0x4000,
+ PARSE_FLAG_STRICT_IGNORABLES = 0x8000,
+};
+
+
+// TODO: Is this class worthwhile?
+template<int32_t stackCapacity>
+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) {
+ uprv_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<UChar, stackCapacity> 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.
+ *
+ * <p>
+ * <strong>What is a strong versus weak char?</strong> 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(UErrorCode& status) const;
+
+ void populateFormattable(Formattable& output, parse_flags_t parseFlags) const;
+
+ bool isBetterThan(const ParsedNumber& other);
+};
+
+
+/**
+ * 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/contrib/libs/icu/i18n/numparse_utils.h b/contrib/libs/icu/i18n/numparse_utils.h
index 162954bae0..9b515d7fa9 100644
--- a/contrib/libs/icu/i18n/numparse_utils.h
+++ b/contrib/libs/icu/i18n/numparse_utils.h
@@ -1,43 +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 */
+// © 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/contrib/libs/icu/i18n/numparse_validators.cpp b/contrib/libs/icu/i18n/numparse_validators.cpp
index 12d3465c4e..d868b06595 100644
--- a/contrib/libs/icu/i18n/numparse_validators.cpp
+++ b/contrib/libs/icu/i18n/numparse_validators.cpp
@@ -1,85 +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"<ReqAffix>";
-}
-
-
-void RequireCurrencyValidator::postProcess(ParsedNumber& result) const {
- if (result.currencyCode[0] == 0) {
- result.flags |= FLAG_FAIL;
- }
-}
-
-UnicodeString RequireCurrencyValidator::toString() const {
- return u"<ReqCurrency>";
-}
-
-
-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"<ReqDecimal>";
-}
-
-
-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"<ReqNumber>";
-}
-
-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"<Scale>";
-}
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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"<ReqAffix>";
+}
+
+
+void RequireCurrencyValidator::postProcess(ParsedNumber& result) const {
+ if (result.currencyCode[0] == 0) {
+ result.flags |= FLAG_FAIL;
+ }
+}
+
+UnicodeString RequireCurrencyValidator::toString() const {
+ return u"<ReqCurrency>";
+}
+
+
+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"<ReqDecimal>";
+}
+
+
+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"<ReqNumber>";
+}
+
+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"<Scale>";
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/numparse_validators.h b/contrib/libs/icu/i18n/numparse_validators.h
index 5d43b779d0..e4633a44ab 100644
--- a/contrib/libs/icu/i18n/numparse_validators.h
+++ b/contrib/libs/icu/i18n/numparse_validators.h
@@ -1,95 +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 */
+// © 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/contrib/libs/icu/i18n/numrange_fluent.cpp b/contrib/libs/icu/i18n/numrange_fluent.cpp
index 33179026f8..ba00d66eed 100644
--- a/contrib/libs/icu/i18n/numrange_fluent.cpp
+++ b/contrib/libs/icu/i18n/numrange_fluent.cpp
@@ -1,402 +1,402 @@
-// © 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 "numrange_impl.h"
-#include "util.h"
-#include "number_utypes.h"
-
-using namespace icu;
-using namespace icu::number;
-using namespace icu::number::impl;
-
-
-// This function needs to be declared in this namespace so it can be friended.
-// NOTE: In Java, this logic is handled in the resolve() function.
-void icu::number::impl::touchRangeLocales(RangeMacroProps& macros) {
- macros.formatter1.fMacros.locale = macros.locale;
- macros.formatter2.fMacros.locale = macros.locale;
-}
-
-
-template<typename Derived>
-Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(const UnlocalizedNumberFormatter& formatter) const& {
- Derived copy(*this);
- copy.fMacros.formatter1 = formatter;
- copy.fMacros.singleFormatter = true;
- touchRangeLocales(copy.fMacros);
- return copy;
-}
-
-template<typename Derived>
-Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(const UnlocalizedNumberFormatter& formatter) && {
- Derived move(std::move(*this));
- move.fMacros.formatter1 = formatter;
- move.fMacros.singleFormatter = true;
- touchRangeLocales(move.fMacros);
- return move;
-}
-
-template<typename Derived>
-Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(UnlocalizedNumberFormatter&& formatter) const& {
- Derived copy(*this);
- copy.fMacros.formatter1 = std::move(formatter);
- copy.fMacros.singleFormatter = true;
- touchRangeLocales(copy.fMacros);
- return copy;
-}
-
-template<typename Derived>
-Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(UnlocalizedNumberFormatter&& formatter) && {
- Derived move(std::move(*this));
- move.fMacros.formatter1 = std::move(formatter);
- move.fMacros.singleFormatter = true;
- touchRangeLocales(move.fMacros);
- return move;
-}
-
-template<typename Derived>
-Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(const UnlocalizedNumberFormatter& formatter) const& {
- Derived copy(*this);
- copy.fMacros.formatter1 = formatter;
- copy.fMacros.singleFormatter = false;
- touchRangeLocales(copy.fMacros);
- return copy;
-}
-
-template<typename Derived>
-Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(const UnlocalizedNumberFormatter& formatter) && {
- Derived move(std::move(*this));
- move.fMacros.formatter1 = formatter;
- move.fMacros.singleFormatter = false;
- touchRangeLocales(move.fMacros);
- return move;
-}
-
-template<typename Derived>
-Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(UnlocalizedNumberFormatter&& formatter) const& {
- Derived copy(*this);
- copy.fMacros.formatter1 = std::move(formatter);
- copy.fMacros.singleFormatter = false;
- touchRangeLocales(copy.fMacros);
- return copy;
-}
-
-template<typename Derived>
-Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(UnlocalizedNumberFormatter&& formatter) && {
- Derived move(std::move(*this));
- move.fMacros.formatter1 = std::move(formatter);
- move.fMacros.singleFormatter = false;
- touchRangeLocales(move.fMacros);
- return move;
-}
-
-template<typename Derived>
-Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(const UnlocalizedNumberFormatter& formatter) const& {
- Derived copy(*this);
- copy.fMacros.formatter2 = formatter;
- copy.fMacros.singleFormatter = false;
- touchRangeLocales(copy.fMacros);
- return copy;
-}
-
-template<typename Derived>
-Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(const UnlocalizedNumberFormatter& formatter) && {
- Derived move(std::move(*this));
- move.fMacros.formatter2 = formatter;
- move.fMacros.singleFormatter = false;
- touchRangeLocales(move.fMacros);
- return move;
-}
-
-template<typename Derived>
-Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(UnlocalizedNumberFormatter&& formatter) const& {
- Derived copy(*this);
- copy.fMacros.formatter2 = std::move(formatter);
- copy.fMacros.singleFormatter = false;
- touchRangeLocales(copy.fMacros);
- return copy;
-}
-
-template<typename Derived>
-Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(UnlocalizedNumberFormatter&& formatter) && {
- Derived move(std::move(*this));
- move.fMacros.formatter2 = std::move(formatter);
- move.fMacros.singleFormatter = false;
- touchRangeLocales(move.fMacros);
- return move;
-}
-
-template<typename Derived>
-Derived NumberRangeFormatterSettings<Derived>::collapse(UNumberRangeCollapse collapse) const& {
- Derived copy(*this);
- copy.fMacros.collapse = collapse;
- return copy;
-}
-
-template<typename Derived>
-Derived NumberRangeFormatterSettings<Derived>::collapse(UNumberRangeCollapse collapse) && {
- Derived move(std::move(*this));
- move.fMacros.collapse = collapse;
- return move;
-}
-
-template<typename Derived>
-Derived NumberRangeFormatterSettings<Derived>::identityFallback(UNumberRangeIdentityFallback identityFallback) const& {
- Derived copy(*this);
- copy.fMacros.identityFallback = identityFallback;
- return copy;
-}
-
-template<typename Derived>
-Derived NumberRangeFormatterSettings<Derived>::identityFallback(UNumberRangeIdentityFallback identityFallback) && {
- Derived move(std::move(*this));
- move.fMacros.identityFallback = identityFallback;
- return move;
-}
-
-template<typename Derived>
-LocalPointer<Derived> NumberRangeFormatterSettings<Derived>::clone() const & {
- return LocalPointer<Derived>(new Derived(*this));
-}
-
-template<typename Derived>
-LocalPointer<Derived> NumberRangeFormatterSettings<Derived>::clone() && {
- return LocalPointer<Derived>(new Derived(std::move(*this)));
-}
-
-// Declare all classes that implement NumberRangeFormatterSettings
-// See https://stackoverflow.com/a/495056/1407170
-template
-class icu::number::NumberRangeFormatterSettings<icu::number::UnlocalizedNumberRangeFormatter>;
-template
-class icu::number::NumberRangeFormatterSettings<icu::number::LocalizedNumberRangeFormatter>;
-
-
-UnlocalizedNumberRangeFormatter NumberRangeFormatter::with() {
- UnlocalizedNumberRangeFormatter result;
- return result;
-}
-
-LocalizedNumberRangeFormatter NumberRangeFormatter::withLocale(const Locale& locale) {
- return with().locale(locale);
-}
-
-
-template<typename T> using NFS = NumberRangeFormatterSettings<T>;
-using LNF = LocalizedNumberRangeFormatter;
-using UNF = UnlocalizedNumberRangeFormatter;
-
-UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const UNF& other)
- : UNF(static_cast<const NFS<UNF>&>(other)) {}
-
-UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const NFS<UNF>& other)
- : NFS<UNF>(other) {
- // No additional fields to assign
-}
-
-// Make default copy constructor call the NumberRangeFormatterSettings copy constructor.
-UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(UNF&& src) U_NOEXCEPT
- : UNF(static_cast<NFS<UNF>&&>(src)) {}
-
-UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(NFS<UNF>&& src) U_NOEXCEPT
- : NFS<UNF>(std::move(src)) {
- // No additional fields to assign
-}
-
-UnlocalizedNumberRangeFormatter& UnlocalizedNumberRangeFormatter::operator=(const UNF& other) {
- NFS<UNF>::operator=(static_cast<const NFS<UNF>&>(other));
- // No additional fields to assign
- return *this;
-}
-
-UnlocalizedNumberRangeFormatter& UnlocalizedNumberRangeFormatter::operator=(UNF&& src) U_NOEXCEPT {
- NFS<UNF>::operator=(static_cast<NFS<UNF>&&>(src));
- // No additional fields to assign
- return *this;
-}
-
-// Make default copy constructor call the NumberRangeFormatterSettings copy constructor.
-LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const LNF& other)
- : LNF(static_cast<const NFS<LNF>&>(other)) {}
-
-LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const NFS<LNF>& other)
- : NFS<LNF>(other) {
- // No additional fields to assign
-}
-
-LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(LocalizedNumberRangeFormatter&& src) U_NOEXCEPT
- : LNF(static_cast<NFS<LNF>&&>(src)) {}
-
-LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(NFS<LNF>&& src) U_NOEXCEPT
- : NFS<LNF>(std::move(src)) {
- // Steal the compiled formatter
- LNF&& _src = static_cast<LNF&&>(src);
- auto* stolen = _src.fAtomicFormatter.exchange(nullptr);
- delete fAtomicFormatter.exchange(stolen);
-}
-
-LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(const LNF& other) {
- NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other));
- // Do not steal; just clear
- delete fAtomicFormatter.exchange(nullptr);
- return *this;
-}
-
-LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(LNF&& src) U_NOEXCEPT {
- NFS<LNF>::operator=(static_cast<NFS<LNF>&&>(src));
- // Steal the compiled formatter
- auto* stolen = src.fAtomicFormatter.exchange(nullptr);
- delete fAtomicFormatter.exchange(stolen);
- return *this;
-}
-
-
-LocalizedNumberRangeFormatter::~LocalizedNumberRangeFormatter() {
- delete fAtomicFormatter.exchange(nullptr);
-}
-
-LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const RangeMacroProps& macros, const Locale& locale) {
- fMacros = macros;
- fMacros.locale = locale;
- touchRangeLocales(fMacros);
-}
-
-LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(RangeMacroProps&& macros, const Locale& locale) {
- fMacros = std::move(macros);
- fMacros.locale = locale;
- touchRangeLocales(fMacros);
-}
-
-LocalizedNumberRangeFormatter UnlocalizedNumberRangeFormatter::locale(const Locale& locale) const& {
- return LocalizedNumberRangeFormatter(fMacros, locale);
-}
-
-LocalizedNumberRangeFormatter UnlocalizedNumberRangeFormatter::locale(const Locale& locale)&& {
- return LocalizedNumberRangeFormatter(std::move(fMacros), locale);
-}
-
-
-FormattedNumberRange LocalizedNumberRangeFormatter::formatFormattableRange(
- const Formattable& first, const Formattable& second, UErrorCode& status) const {
- if (U_FAILURE(status)) {
- return FormattedNumberRange(U_ILLEGAL_ARGUMENT_ERROR);
- }
-
- auto results = new UFormattedNumberRangeData();
- if (results == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return FormattedNumberRange(status);
- }
-
- first.populateDecimalQuantity(results->quantity1, status);
- if (U_FAILURE(status)) {
- return FormattedNumberRange(status);
- }
-
- second.populateDecimalQuantity(results->quantity2, status);
- if (U_FAILURE(status)) {
- return FormattedNumberRange(status);
- }
-
- formatImpl(*results, first == second, status);
-
- // Do not save the results object if we encountered a failure.
- if (U_SUCCESS(status)) {
- return FormattedNumberRange(results);
- } else {
- delete results;
- return FormattedNumberRange(status);
- }
-}
-
-void LocalizedNumberRangeFormatter::formatImpl(
- UFormattedNumberRangeData& results, bool equalBeforeRounding, UErrorCode& status) const {
- auto* impl = getFormatter(status);
- if (U_FAILURE(status)) {
- return;
- }
- if (impl == nullptr) {
- status = U_INTERNAL_PROGRAM_ERROR;
- return;
- }
- impl->format(results, equalBeforeRounding, status);
- if (U_FAILURE(status)) {
- return;
- }
- results.getStringRef().writeTerminator(status);
-}
-
-const impl::NumberRangeFormatterImpl*
-LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const {
- // TODO: Move this into umutex.h? (similar logic also in decimfmt.cpp)
- // See ICU-20146
-
- if (U_FAILURE(status)) {
- return nullptr;
- }
-
- // First try to get the pre-computed formatter
- auto* ptr = fAtomicFormatter.load();
- if (ptr != nullptr) {
- return ptr;
- }
-
- // Try computing the formatter on our own
- auto* temp = new NumberRangeFormatterImpl(fMacros, status);
- if (U_FAILURE(status)) {
- return nullptr;
- }
- if (temp == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
-
- // 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 formatter object.
- auto* nonConstThis = const_cast<LocalizedNumberRangeFormatter*>(this);
- if (!nonConstThis->fAtomicFormatter.compare_exchange_strong(ptr, temp)) {
- // Another thread beat us to computing the formatter
- delete temp;
- return ptr;
- } else {
- // Our copy of the formatter got stored in the atomic
- return temp;
- }
-
-}
-
-
-UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(FormattedNumberRange)
-
-#define UPRV_NOARG
-
-UnicodeString FormattedNumberRange::getFirstDecimal(UErrorCode& status) const {
- UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString())
- return fData->quantity1.toScientificString();
-}
-
-UnicodeString FormattedNumberRange::getSecondDecimal(UErrorCode& status) const {
- UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString())
- return fData->quantity2.toScientificString();
-}
-
-UNumberRangeIdentityResult FormattedNumberRange::getIdentityResult(UErrorCode& status) const {
- UPRV_FORMATTED_VALUE_METHOD_GUARD(UNUM_IDENTITY_RESULT_NOT_EQUAL)
- return fData->identityResult;
-}
-
-
-UFormattedNumberRangeData::~UFormattedNumberRangeData() = default;
-
-
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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 "numrange_impl.h"
+#include "util.h"
+#include "number_utypes.h"
+
+using namespace icu;
+using namespace icu::number;
+using namespace icu::number::impl;
+
+
+// This function needs to be declared in this namespace so it can be friended.
+// NOTE: In Java, this logic is handled in the resolve() function.
+void icu::number::impl::touchRangeLocales(RangeMacroProps& macros) {
+ macros.formatter1.fMacros.locale = macros.locale;
+ macros.formatter2.fMacros.locale = macros.locale;
+}
+
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(const UnlocalizedNumberFormatter& formatter) const& {
+ Derived copy(*this);
+ copy.fMacros.formatter1 = formatter;
+ copy.fMacros.singleFormatter = true;
+ touchRangeLocales(copy.fMacros);
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(const UnlocalizedNumberFormatter& formatter) && {
+ Derived move(std::move(*this));
+ move.fMacros.formatter1 = formatter;
+ move.fMacros.singleFormatter = true;
+ touchRangeLocales(move.fMacros);
+ return move;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(UnlocalizedNumberFormatter&& formatter) const& {
+ Derived copy(*this);
+ copy.fMacros.formatter1 = std::move(formatter);
+ copy.fMacros.singleFormatter = true;
+ touchRangeLocales(copy.fMacros);
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(UnlocalizedNumberFormatter&& formatter) && {
+ Derived move(std::move(*this));
+ move.fMacros.formatter1 = std::move(formatter);
+ move.fMacros.singleFormatter = true;
+ touchRangeLocales(move.fMacros);
+ return move;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(const UnlocalizedNumberFormatter& formatter) const& {
+ Derived copy(*this);
+ copy.fMacros.formatter1 = formatter;
+ copy.fMacros.singleFormatter = false;
+ touchRangeLocales(copy.fMacros);
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(const UnlocalizedNumberFormatter& formatter) && {
+ Derived move(std::move(*this));
+ move.fMacros.formatter1 = formatter;
+ move.fMacros.singleFormatter = false;
+ touchRangeLocales(move.fMacros);
+ return move;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(UnlocalizedNumberFormatter&& formatter) const& {
+ Derived copy(*this);
+ copy.fMacros.formatter1 = std::move(formatter);
+ copy.fMacros.singleFormatter = false;
+ touchRangeLocales(copy.fMacros);
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(UnlocalizedNumberFormatter&& formatter) && {
+ Derived move(std::move(*this));
+ move.fMacros.formatter1 = std::move(formatter);
+ move.fMacros.singleFormatter = false;
+ touchRangeLocales(move.fMacros);
+ return move;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(const UnlocalizedNumberFormatter& formatter) const& {
+ Derived copy(*this);
+ copy.fMacros.formatter2 = formatter;
+ copy.fMacros.singleFormatter = false;
+ touchRangeLocales(copy.fMacros);
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(const UnlocalizedNumberFormatter& formatter) && {
+ Derived move(std::move(*this));
+ move.fMacros.formatter2 = formatter;
+ move.fMacros.singleFormatter = false;
+ touchRangeLocales(move.fMacros);
+ return move;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(UnlocalizedNumberFormatter&& formatter) const& {
+ Derived copy(*this);
+ copy.fMacros.formatter2 = std::move(formatter);
+ copy.fMacros.singleFormatter = false;
+ touchRangeLocales(copy.fMacros);
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(UnlocalizedNumberFormatter&& formatter) && {
+ Derived move(std::move(*this));
+ move.fMacros.formatter2 = std::move(formatter);
+ move.fMacros.singleFormatter = false;
+ touchRangeLocales(move.fMacros);
+ return move;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::collapse(UNumberRangeCollapse collapse) const& {
+ Derived copy(*this);
+ copy.fMacros.collapse = collapse;
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::collapse(UNumberRangeCollapse collapse) && {
+ Derived move(std::move(*this));
+ move.fMacros.collapse = collapse;
+ return move;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::identityFallback(UNumberRangeIdentityFallback identityFallback) const& {
+ Derived copy(*this);
+ copy.fMacros.identityFallback = identityFallback;
+ return copy;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::identityFallback(UNumberRangeIdentityFallback identityFallback) && {
+ Derived move(std::move(*this));
+ move.fMacros.identityFallback = identityFallback;
+ return move;
+}
+
+template<typename Derived>
+LocalPointer<Derived> NumberRangeFormatterSettings<Derived>::clone() const & {
+ return LocalPointer<Derived>(new Derived(*this));
+}
+
+template<typename Derived>
+LocalPointer<Derived> NumberRangeFormatterSettings<Derived>::clone() && {
+ return LocalPointer<Derived>(new Derived(std::move(*this)));
+}
+
+// Declare all classes that implement NumberRangeFormatterSettings
+// See https://stackoverflow.com/a/495056/1407170
+template
+class icu::number::NumberRangeFormatterSettings<icu::number::UnlocalizedNumberRangeFormatter>;
+template
+class icu::number::NumberRangeFormatterSettings<icu::number::LocalizedNumberRangeFormatter>;
+
+
+UnlocalizedNumberRangeFormatter NumberRangeFormatter::with() {
+ UnlocalizedNumberRangeFormatter result;
+ return result;
+}
+
+LocalizedNumberRangeFormatter NumberRangeFormatter::withLocale(const Locale& locale) {
+ return with().locale(locale);
+}
+
+
+template<typename T> using NFS = NumberRangeFormatterSettings<T>;
+using LNF = LocalizedNumberRangeFormatter;
+using UNF = UnlocalizedNumberRangeFormatter;
+
+UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const UNF& other)
+ : UNF(static_cast<const NFS<UNF>&>(other)) {}
+
+UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const NFS<UNF>& other)
+ : NFS<UNF>(other) {
+ // No additional fields to assign
+}
+
+// Make default copy constructor call the NumberRangeFormatterSettings copy constructor.
+UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(UNF&& src) U_NOEXCEPT
+ : UNF(static_cast<NFS<UNF>&&>(src)) {}
+
+UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(NFS<UNF>&& src) U_NOEXCEPT
+ : NFS<UNF>(std::move(src)) {
+ // No additional fields to assign
+}
+
+UnlocalizedNumberRangeFormatter& UnlocalizedNumberRangeFormatter::operator=(const UNF& other) {
+ NFS<UNF>::operator=(static_cast<const NFS<UNF>&>(other));
+ // No additional fields to assign
+ return *this;
+}
+
+UnlocalizedNumberRangeFormatter& UnlocalizedNumberRangeFormatter::operator=(UNF&& src) U_NOEXCEPT {
+ NFS<UNF>::operator=(static_cast<NFS<UNF>&&>(src));
+ // No additional fields to assign
+ return *this;
+}
+
+// Make default copy constructor call the NumberRangeFormatterSettings copy constructor.
+LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const LNF& other)
+ : LNF(static_cast<const NFS<LNF>&>(other)) {}
+
+LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const NFS<LNF>& other)
+ : NFS<LNF>(other) {
+ // No additional fields to assign
+}
+
+LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(LocalizedNumberRangeFormatter&& src) U_NOEXCEPT
+ : LNF(static_cast<NFS<LNF>&&>(src)) {}
+
+LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(NFS<LNF>&& src) U_NOEXCEPT
+ : NFS<LNF>(std::move(src)) {
+ // Steal the compiled formatter
+ LNF&& _src = static_cast<LNF&&>(src);
+ auto* stolen = _src.fAtomicFormatter.exchange(nullptr);
+ delete fAtomicFormatter.exchange(stolen);
+}
+
+LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(const LNF& other) {
+ NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other));
+ // Do not steal; just clear
+ delete fAtomicFormatter.exchange(nullptr);
+ return *this;
+}
+
+LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(LNF&& src) U_NOEXCEPT {
+ NFS<LNF>::operator=(static_cast<NFS<LNF>&&>(src));
+ // Steal the compiled formatter
+ auto* stolen = src.fAtomicFormatter.exchange(nullptr);
+ delete fAtomicFormatter.exchange(stolen);
+ return *this;
+}
+
+
+LocalizedNumberRangeFormatter::~LocalizedNumberRangeFormatter() {
+ delete fAtomicFormatter.exchange(nullptr);
+}
+
+LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const RangeMacroProps& macros, const Locale& locale) {
+ fMacros = macros;
+ fMacros.locale = locale;
+ touchRangeLocales(fMacros);
+}
+
+LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(RangeMacroProps&& macros, const Locale& locale) {
+ fMacros = std::move(macros);
+ fMacros.locale = locale;
+ touchRangeLocales(fMacros);
+}
+
+LocalizedNumberRangeFormatter UnlocalizedNumberRangeFormatter::locale(const Locale& locale) const& {
+ return LocalizedNumberRangeFormatter(fMacros, locale);
+}
+
+LocalizedNumberRangeFormatter UnlocalizedNumberRangeFormatter::locale(const Locale& locale)&& {
+ return LocalizedNumberRangeFormatter(std::move(fMacros), locale);
+}
+
+
+FormattedNumberRange LocalizedNumberRangeFormatter::formatFormattableRange(
+ const Formattable& first, const Formattable& second, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return FormattedNumberRange(U_ILLEGAL_ARGUMENT_ERROR);
+ }
+
+ auto results = new UFormattedNumberRangeData();
+ if (results == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return FormattedNumberRange(status);
+ }
+
+ first.populateDecimalQuantity(results->quantity1, status);
+ if (U_FAILURE(status)) {
+ return FormattedNumberRange(status);
+ }
+
+ second.populateDecimalQuantity(results->quantity2, status);
+ if (U_FAILURE(status)) {
+ return FormattedNumberRange(status);
+ }
+
+ formatImpl(*results, first == second, status);
+
+ // Do not save the results object if we encountered a failure.
+ if (U_SUCCESS(status)) {
+ return FormattedNumberRange(results);
+ } else {
+ delete results;
+ return FormattedNumberRange(status);
+ }
+}
+
+void LocalizedNumberRangeFormatter::formatImpl(
+ UFormattedNumberRangeData& results, bool equalBeforeRounding, UErrorCode& status) const {
+ auto* impl = getFormatter(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (impl == nullptr) {
+ status = U_INTERNAL_PROGRAM_ERROR;
+ return;
+ }
+ impl->format(results, equalBeforeRounding, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ results.getStringRef().writeTerminator(status);
+}
+
+const impl::NumberRangeFormatterImpl*
+LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const {
+ // TODO: Move this into umutex.h? (similar logic also in decimfmt.cpp)
+ // See ICU-20146
+
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+
+ // First try to get the pre-computed formatter
+ auto* ptr = fAtomicFormatter.load();
+ if (ptr != nullptr) {
+ return ptr;
+ }
+
+ // Try computing the formatter on our own
+ auto* temp = new NumberRangeFormatterImpl(fMacros, status);
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ if (temp == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+
+ // 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 formatter object.
+ auto* nonConstThis = const_cast<LocalizedNumberRangeFormatter*>(this);
+ if (!nonConstThis->fAtomicFormatter.compare_exchange_strong(ptr, temp)) {
+ // Another thread beat us to computing the formatter
+ delete temp;
+ return ptr;
+ } else {
+ // Our copy of the formatter got stored in the atomic
+ return temp;
+ }
+
+}
+
+
+UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(FormattedNumberRange)
+
+#define UPRV_NOARG
+
+UnicodeString FormattedNumberRange::getFirstDecimal(UErrorCode& status) const {
+ UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString())
+ return fData->quantity1.toScientificString();
+}
+
+UnicodeString FormattedNumberRange::getSecondDecimal(UErrorCode& status) const {
+ UPRV_FORMATTED_VALUE_METHOD_GUARD(ICU_Utility::makeBogusString())
+ return fData->quantity2.toScientificString();
+}
+
+UNumberRangeIdentityResult FormattedNumberRange::getIdentityResult(UErrorCode& status) const {
+ UPRV_FORMATTED_VALUE_METHOD_GUARD(UNUM_IDENTITY_RESULT_NOT_EQUAL)
+ return fData->identityResult;
+}
+
+
+UFormattedNumberRangeData::~UFormattedNumberRangeData() = default;
+
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/numrange_impl.cpp b/contrib/libs/icu/i18n/numrange_impl.cpp
index 9fb3dee861..023bfd01f7 100644
--- a/contrib/libs/icu/i18n/numrange_impl.cpp
+++ b/contrib/libs/icu/i18n/numrange_impl.cpp
@@ -1,508 +1,508 @@
-// © 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 "unicode/numberrangeformatter.h"
-#include "numrange_impl.h"
-#include "patternprops.h"
-#include "uresimp.h"
-#include "util.h"
-
-using namespace icu;
-using namespace icu::number;
-using namespace icu::number::impl;
-
-namespace {
-
-// Helper function for 2-dimensional switch statement
-constexpr int8_t identity2d(UNumberRangeIdentityFallback a, UNumberRangeIdentityResult b) {
- return static_cast<int8_t>(a) | (static_cast<int8_t>(b) << 4);
-}
-
-
-struct NumberRangeData {
- SimpleFormatter rangePattern;
- SimpleFormatter approximatelyPattern;
-};
-
-class NumberRangeDataSink : public ResourceSink {
- public:
- NumberRangeDataSink(NumberRangeData& data) : fData(data) {}
-
- void put(const char* key, ResourceValue& value, UBool /*noFallback*/, UErrorCode& status) U_OVERRIDE {
- ResourceTable miscTable = value.getTable(status);
- if (U_FAILURE(status)) { return; }
- for (int i = 0; miscTable.getKeyAndValue(i, key, value); i++) {
- if (uprv_strcmp(key, "range") == 0) {
- if (hasRangeData()) {
- continue; // have already seen this pattern
- }
- fData.rangePattern = {value.getUnicodeString(status), status};
- } else if (uprv_strcmp(key, "approximately") == 0) {
- if (hasApproxData()) {
- continue; // have already seen this pattern
- }
- fData.approximatelyPattern = {value.getUnicodeString(status), status};
- }
- }
- }
-
- bool hasRangeData() {
- return fData.rangePattern.getArgumentLimit() != 0;
- }
-
- bool hasApproxData() {
- return fData.approximatelyPattern.getArgumentLimit() != 0;
- }
-
- bool isComplete() {
- return hasRangeData() && hasApproxData();
- }
-
- void fillInDefaults(UErrorCode& status) {
- if (!hasRangeData()) {
- fData.rangePattern = {u"{0}–{1}", status};
- }
- if (!hasApproxData()) {
- fData.approximatelyPattern = {u"~{0}", status};
- }
- }
-
- private:
- NumberRangeData& fData;
-};
-
-void getNumberRangeData(const char* localeName, const char* nsName, NumberRangeData& data, UErrorCode& status) {
- if (U_FAILURE(status)) { return; }
- LocalUResourceBundlePointer rb(ures_open(NULL, localeName, &status));
- if (U_FAILURE(status)) { return; }
- NumberRangeDataSink sink(data);
-
- CharString dataPath;
- dataPath.append("NumberElements/", -1, status);
- dataPath.append(nsName, -1, status);
- dataPath.append("/miscPatterns", -1, status);
- if (U_FAILURE(status)) { return; }
-
- UErrorCode localStatus = U_ZERO_ERROR;
- ures_getAllItemsWithFallback(rb.getAlias(), dataPath.data(), sink, localStatus);
- if (U_FAILURE(localStatus) && localStatus != U_MISSING_RESOURCE_ERROR) {
- status = localStatus;
- return;
- }
-
- // Fall back to latn if necessary
- if (!sink.isComplete()) {
- ures_getAllItemsWithFallback(rb.getAlias(), "NumberElements/latn/miscPatterns", sink, status);
- }
-
- sink.fillInDefaults(status);
-}
-
-class PluralRangesDataSink : public ResourceSink {
- public:
- PluralRangesDataSink(StandardPluralRanges& output) : fOutput(output) {}
-
- void put(const char* /*key*/, ResourceValue& value, UBool /*noFallback*/, UErrorCode& status) U_OVERRIDE {
- ResourceArray entriesArray = value.getArray(status);
- if (U_FAILURE(status)) { return; }
- fOutput.setCapacity(entriesArray.getSize());
- for (int i = 0; entriesArray.getValue(i, value); i++) {
- ResourceArray pluralFormsArray = value.getArray(status);
- if (U_FAILURE(status)) { return; }
- pluralFormsArray.getValue(0, value);
- StandardPlural::Form first = StandardPlural::fromString(value.getUnicodeString(status), status);
- if (U_FAILURE(status)) { return; }
- pluralFormsArray.getValue(1, value);
- StandardPlural::Form second = StandardPlural::fromString(value.getUnicodeString(status), status);
- if (U_FAILURE(status)) { return; }
- pluralFormsArray.getValue(2, value);
- StandardPlural::Form result = StandardPlural::fromString(value.getUnicodeString(status), status);
- if (U_FAILURE(status)) { return; }
- fOutput.addPluralRange(first, second, result);
- }
- }
-
- private:
- StandardPluralRanges& fOutput;
-};
-
-void getPluralRangesData(const Locale& locale, StandardPluralRanges& output, UErrorCode& status) {
- if (U_FAILURE(status)) { return; }
- LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "pluralRanges", &status));
- if (U_FAILURE(status)) { return; }
-
- CharString dataPath;
- dataPath.append("locales/", -1, status);
- dataPath.append(locale.getLanguage(), -1, status);
- if (U_FAILURE(status)) { return; }
- int32_t setLen;
- // Not all languages are covered: fail gracefully
- UErrorCode internalStatus = U_ZERO_ERROR;
- const UChar* set = ures_getStringByKeyWithFallback(rb.getAlias(), dataPath.data(), &setLen, &internalStatus);
- if (U_FAILURE(internalStatus)) { return; }
-
- dataPath.clear();
- dataPath.append("rules/", -1, status);
- dataPath.appendInvariantChars(set, setLen, status);
- if (U_FAILURE(status)) { return; }
- PluralRangesDataSink sink(output);
- ures_getAllItemsWithFallback(rb.getAlias(), dataPath.data(), sink, status);
- if (U_FAILURE(status)) { return; }
-}
-
-} // namespace
-
-
-void StandardPluralRanges::initialize(const Locale& locale, UErrorCode& status) {
- getPluralRangesData(locale, *this, status);
-}
-
-void StandardPluralRanges::addPluralRange(
- StandardPlural::Form first,
- StandardPlural::Form second,
- StandardPlural::Form result) {
- U_ASSERT(fTriplesLen < fTriples.getCapacity());
- fTriples[fTriplesLen] = {first, second, result};
- fTriplesLen++;
-}
-
-void StandardPluralRanges::setCapacity(int32_t length) {
- if (length > fTriples.getCapacity()) {
- fTriples.resize(length, 0);
- }
-}
-
-StandardPlural::Form
-StandardPluralRanges::resolve(StandardPlural::Form first, StandardPlural::Form second) const {
- for (int32_t i=0; i<fTriplesLen; i++) {
- const auto& triple = fTriples[i];
- if (triple.first == first && triple.second == second) {
- return triple.result;
- }
- }
- // Default fallback
- return StandardPlural::OTHER;
-}
-
-
-NumberRangeFormatterImpl::NumberRangeFormatterImpl(const RangeMacroProps& macros, UErrorCode& status)
- : formatterImpl1(macros.formatter1.fMacros, status),
- formatterImpl2(macros.formatter2.fMacros, status),
- fSameFormatters(macros.singleFormatter),
- fCollapse(macros.collapse),
- fIdentityFallback(macros.identityFallback) {
-
- const char* nsName = formatterImpl1.getRawMicroProps().nsName;
- if (uprv_strcmp(nsName, formatterImpl2.getRawMicroProps().nsName) != 0) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return;
- }
-
- NumberRangeData data;
- getNumberRangeData(macros.locale.getName(), nsName, data, status);
- if (U_FAILURE(status)) { return; }
- fRangeFormatter = data.rangePattern;
- fApproximatelyModifier = {data.approximatelyPattern, kUndefinedField, false};
-
- // TODO: Get locale from PluralRules instead?
- fPluralRanges.initialize(macros.locale, status);
- if (U_FAILURE(status)) { return; }
-}
-
-void NumberRangeFormatterImpl::format(UFormattedNumberRangeData& data, bool equalBeforeRounding, UErrorCode& status) const {
- if (U_FAILURE(status)) {
- return;
- }
-
- MicroProps micros1;
- MicroProps micros2;
- formatterImpl1.preProcess(data.quantity1, micros1, status);
- if (fSameFormatters) {
- formatterImpl1.preProcess(data.quantity2, micros2, status);
- } else {
- formatterImpl2.preProcess(data.quantity2, micros2, status);
- }
- if (U_FAILURE(status)) {
- return;
- }
-
- // If any of the affixes are different, an identity is not possible
- // and we must use formatRange().
- // TODO: Write this as MicroProps operator==() ?
- // TODO: Avoid the redundancy of these equality operations with the
- // ones in formatRange?
- if (!micros1.modInner->semanticallyEquivalent(*micros2.modInner)
- || !micros1.modMiddle->semanticallyEquivalent(*micros2.modMiddle)
- || !micros1.modOuter->semanticallyEquivalent(*micros2.modOuter)) {
- formatRange(data, micros1, micros2, status);
- data.identityResult = UNUM_IDENTITY_RESULT_NOT_EQUAL;
- return;
- }
-
- // Check for identity
- if (equalBeforeRounding) {
- data.identityResult = UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING;
- } else if (data.quantity1 == data.quantity2) {
- data.identityResult = UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING;
- } else {
- data.identityResult = UNUM_IDENTITY_RESULT_NOT_EQUAL;
- }
-
- switch (identity2d(fIdentityFallback, data.identityResult)) {
- case identity2d(UNUM_IDENTITY_FALLBACK_RANGE,
- UNUM_IDENTITY_RESULT_NOT_EQUAL):
- case identity2d(UNUM_IDENTITY_FALLBACK_RANGE,
- UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING):
- case identity2d(UNUM_IDENTITY_FALLBACK_RANGE,
- UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING):
- case identity2d(UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
- UNUM_IDENTITY_RESULT_NOT_EQUAL):
- case identity2d(UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE,
- UNUM_IDENTITY_RESULT_NOT_EQUAL):
- case identity2d(UNUM_IDENTITY_FALLBACK_SINGLE_VALUE,
- UNUM_IDENTITY_RESULT_NOT_EQUAL):
- formatRange(data, micros1, micros2, status);
- break;
-
- case identity2d(UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
- UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING):
- case identity2d(UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
- UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING):
- case identity2d(UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE,
- UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING):
- formatApproximately(data, micros1, micros2, status);
- break;
-
- case identity2d(UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE,
- UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING):
- case identity2d(UNUM_IDENTITY_FALLBACK_SINGLE_VALUE,
- UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING):
- case identity2d(UNUM_IDENTITY_FALLBACK_SINGLE_VALUE,
- UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING):
- formatSingleValue(data, micros1, micros2, status);
- break;
-
- default:
- UPRV_UNREACHABLE;
- }
-}
-
-
-void NumberRangeFormatterImpl::formatSingleValue(UFormattedNumberRangeData& data,
- MicroProps& micros1, MicroProps& micros2,
- UErrorCode& status) const {
- if (U_FAILURE(status)) { return; }
- if (fSameFormatters) {
- int32_t length = NumberFormatterImpl::writeNumber(micros1, data.quantity1, data.getStringRef(), 0, status);
- NumberFormatterImpl::writeAffixes(micros1, data.getStringRef(), 0, length, status);
- } else {
- formatRange(data, micros1, micros2, status);
- }
-}
-
-
-void NumberRangeFormatterImpl::formatApproximately (UFormattedNumberRangeData& data,
- MicroProps& micros1, MicroProps& micros2,
- UErrorCode& status) const {
- if (U_FAILURE(status)) { return; }
- if (fSameFormatters) {
- int32_t length = NumberFormatterImpl::writeNumber(micros1, data.quantity1, data.getStringRef(), 0, status);
- // HEURISTIC: Desired modifier order: inner, middle, approximately, outer.
- length += micros1.modInner->apply(data.getStringRef(), 0, length, status);
- length += micros1.modMiddle->apply(data.getStringRef(), 0, length, status);
- length += fApproximatelyModifier.apply(data.getStringRef(), 0, length, status);
- micros1.modOuter->apply(data.getStringRef(), 0, length, status);
- } else {
- formatRange(data, micros1, micros2, status);
- }
-}
-
-
-void NumberRangeFormatterImpl::formatRange(UFormattedNumberRangeData& data,
- MicroProps& micros1, MicroProps& micros2,
- UErrorCode& status) const {
- if (U_FAILURE(status)) { return; }
-
- // modInner is always notation (scientific); collapsable in ALL.
- // modOuter is always units; collapsable in ALL, AUTO, and UNIT.
- // modMiddle could be either; collapsable in ALL and sometimes AUTO and UNIT.
- // Never collapse an outer mod but not an inner mod.
- bool collapseOuter, collapseMiddle, collapseInner;
- switch (fCollapse) {
- case UNUM_RANGE_COLLAPSE_ALL:
- case UNUM_RANGE_COLLAPSE_AUTO:
- case UNUM_RANGE_COLLAPSE_UNIT:
- {
- // OUTER MODIFIER
- collapseOuter = micros1.modOuter->semanticallyEquivalent(*micros2.modOuter);
-
- if (!collapseOuter) {
- // Never collapse inner mods if outer mods are not collapsable
- collapseMiddle = false;
- collapseInner = false;
- break;
- }
-
- // MIDDLE MODIFIER
- collapseMiddle = micros1.modMiddle->semanticallyEquivalent(*micros2.modMiddle);
-
- if (!collapseMiddle) {
- // Never collapse inner mods if outer mods are not collapsable
- collapseInner = false;
- break;
- }
-
- // MIDDLE MODIFIER HEURISTICS
- // (could disable collapsing of the middle modifier)
- // The modifiers are equal by this point, so we can look at just one of them.
- const Modifier* mm = micros1.modMiddle;
- if (fCollapse == UNUM_RANGE_COLLAPSE_UNIT) {
- // Only collapse if the modifier is a unit.
- // TODO: Make a better way to check for a unit?
- // TODO: Handle case where the modifier has both notation and unit (compact currency)?
- if (!mm->containsField({UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD})
- && !mm->containsField({UFIELD_CATEGORY_NUMBER, UNUM_PERCENT_FIELD})) {
- collapseMiddle = false;
- }
- } else if (fCollapse == UNUM_RANGE_COLLAPSE_AUTO) {
- // Heuristic as of ICU 63: collapse only if the modifier is more than one code point.
- if (mm->getCodePointCount() <= 1) {
- collapseMiddle = false;
- }
- }
-
- if (!collapseMiddle || fCollapse != UNUM_RANGE_COLLAPSE_ALL) {
- collapseInner = false;
- break;
- }
-
- // INNER MODIFIER
- collapseInner = micros1.modInner->semanticallyEquivalent(*micros2.modInner);
-
- // All done checking for collapsability.
- break;
- }
-
- default:
- collapseOuter = false;
- collapseMiddle = false;
- collapseInner = false;
- break;
- }
-
- FormattedStringBuilder& string = data.getStringRef();
- int32_t lengthPrefix = 0;
- int32_t length1 = 0;
- int32_t lengthInfix = 0;
- int32_t length2 = 0;
- int32_t lengthSuffix = 0;
-
- // Use #define so that these are evaluated at the call site.
- #define UPRV_INDEX_0 (lengthPrefix)
- #define UPRV_INDEX_1 (lengthPrefix + length1)
- #define UPRV_INDEX_2 (lengthPrefix + length1 + lengthInfix)
- #define UPRV_INDEX_3 (lengthPrefix + length1 + lengthInfix + length2)
-
- int32_t lengthRange = SimpleModifier::formatTwoArgPattern(
- fRangeFormatter,
- string,
- 0,
- &lengthPrefix,
- &lengthSuffix,
- kUndefinedField,
- status);
- if (U_FAILURE(status)) { return; }
- lengthInfix = lengthRange - lengthPrefix - lengthSuffix;
- U_ASSERT(lengthInfix > 0);
-
- // SPACING HEURISTIC
- // Add spacing unless all modifiers are collapsed.
- // TODO: add API to control this?
- // TODO: Use a data-driven heuristic like currency spacing?
- // TODO: Use Unicode [:whitespace:] instead of PatternProps whitespace? (consider speed implications)
- {
- bool repeatInner = !collapseInner && micros1.modInner->getCodePointCount() > 0;
- bool repeatMiddle = !collapseMiddle && micros1.modMiddle->getCodePointCount() > 0;
- bool repeatOuter = !collapseOuter && micros1.modOuter->getCodePointCount() > 0;
- if (repeatInner || repeatMiddle || repeatOuter) {
- // Add spacing if there is not already spacing
- if (!PatternProps::isWhiteSpace(string.charAt(UPRV_INDEX_1))) {
- lengthInfix += string.insertCodePoint(UPRV_INDEX_1, u'\u0020', kUndefinedField, status);
- }
- if (!PatternProps::isWhiteSpace(string.charAt(UPRV_INDEX_2 - 1))) {
- lengthInfix += string.insertCodePoint(UPRV_INDEX_2, u'\u0020', kUndefinedField, status);
- }
- }
- }
-
- length1 += NumberFormatterImpl::writeNumber(micros1, data.quantity1, string, UPRV_INDEX_0, status);
- length2 += NumberFormatterImpl::writeNumber(micros2, data.quantity2, string, UPRV_INDEX_2, status);
-
- // TODO: Support padding?
-
- if (collapseInner) {
- // Note: this is actually a mix of prefix and suffix, but adding to infix length works
- const Modifier& mod = resolveModifierPlurals(*micros1.modInner, *micros2.modInner);
- lengthInfix += mod.apply(string, UPRV_INDEX_0, UPRV_INDEX_3, status);
- } else {
- length1 += micros1.modInner->apply(string, UPRV_INDEX_0, UPRV_INDEX_1, status);
- length2 += micros2.modInner->apply(string, UPRV_INDEX_2, UPRV_INDEX_3, status);
- }
-
- if (collapseMiddle) {
- // Note: this is actually a mix of prefix and suffix, but adding to infix length works
- const Modifier& mod = resolveModifierPlurals(*micros1.modMiddle, *micros2.modMiddle);
- lengthInfix += mod.apply(string, UPRV_INDEX_0, UPRV_INDEX_3, status);
- } else {
- length1 += micros1.modMiddle->apply(string, UPRV_INDEX_0, UPRV_INDEX_1, status);
- length2 += micros2.modMiddle->apply(string, UPRV_INDEX_2, UPRV_INDEX_3, status);
- }
-
- if (collapseOuter) {
- // Note: this is actually a mix of prefix and suffix, but adding to infix length works
- const Modifier& mod = resolveModifierPlurals(*micros1.modOuter, *micros2.modOuter);
- lengthInfix += mod.apply(string, UPRV_INDEX_0, UPRV_INDEX_3, status);
- } else {
- length1 += micros1.modOuter->apply(string, UPRV_INDEX_0, UPRV_INDEX_1, status);
- length2 += micros2.modOuter->apply(string, UPRV_INDEX_2, UPRV_INDEX_3, status);
- }
-}
-
-
-const Modifier&
-NumberRangeFormatterImpl::resolveModifierPlurals(const Modifier& first, const Modifier& second) const {
- Modifier::Parameters parameters;
- first.getParameters(parameters);
- if (parameters.obj == nullptr) {
- // No plural form; return a fallback (e.g., the first)
- return first;
- }
- StandardPlural::Form firstPlural = parameters.plural;
-
- second.getParameters(parameters);
- if (parameters.obj == nullptr) {
- // No plural form; return a fallback (e.g., the first)
- return first;
- }
- StandardPlural::Form secondPlural = parameters.plural;
-
- // Get the required plural form from data
- StandardPlural::Form resultPlural = fPluralRanges.resolve(firstPlural, secondPlural);
-
- // Get and return the new Modifier
- const Modifier* mod = parameters.obj->getModifier(parameters.signum, resultPlural);
- U_ASSERT(mod != nullptr);
- return *mod;
-}
-
-
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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 "unicode/numberrangeformatter.h"
+#include "numrange_impl.h"
+#include "patternprops.h"
+#include "uresimp.h"
+#include "util.h"
+
+using namespace icu;
+using namespace icu::number;
+using namespace icu::number::impl;
+
+namespace {
+
+// Helper function for 2-dimensional switch statement
+constexpr int8_t identity2d(UNumberRangeIdentityFallback a, UNumberRangeIdentityResult b) {
+ return static_cast<int8_t>(a) | (static_cast<int8_t>(b) << 4);
+}
+
+
+struct NumberRangeData {
+ SimpleFormatter rangePattern;
+ SimpleFormatter approximatelyPattern;
+};
+
+class NumberRangeDataSink : public ResourceSink {
+ public:
+ NumberRangeDataSink(NumberRangeData& data) : fData(data) {}
+
+ void put(const char* key, ResourceValue& value, UBool /*noFallback*/, UErrorCode& status) U_OVERRIDE {
+ ResourceTable miscTable = value.getTable(status);
+ if (U_FAILURE(status)) { return; }
+ for (int i = 0; miscTable.getKeyAndValue(i, key, value); i++) {
+ if (uprv_strcmp(key, "range") == 0) {
+ if (hasRangeData()) {
+ continue; // have already seen this pattern
+ }
+ fData.rangePattern = {value.getUnicodeString(status), status};
+ } else if (uprv_strcmp(key, "approximately") == 0) {
+ if (hasApproxData()) {
+ continue; // have already seen this pattern
+ }
+ fData.approximatelyPattern = {value.getUnicodeString(status), status};
+ }
+ }
+ }
+
+ bool hasRangeData() {
+ return fData.rangePattern.getArgumentLimit() != 0;
+ }
+
+ bool hasApproxData() {
+ return fData.approximatelyPattern.getArgumentLimit() != 0;
+ }
+
+ bool isComplete() {
+ return hasRangeData() && hasApproxData();
+ }
+
+ void fillInDefaults(UErrorCode& status) {
+ if (!hasRangeData()) {
+ fData.rangePattern = {u"{0}–{1}", status};
+ }
+ if (!hasApproxData()) {
+ fData.approximatelyPattern = {u"~{0}", status};
+ }
+ }
+
+ private:
+ NumberRangeData& fData;
+};
+
+void getNumberRangeData(const char* localeName, const char* nsName, NumberRangeData& data, UErrorCode& status) {
+ if (U_FAILURE(status)) { return; }
+ LocalUResourceBundlePointer rb(ures_open(NULL, localeName, &status));
+ if (U_FAILURE(status)) { return; }
+ NumberRangeDataSink sink(data);
+
+ CharString dataPath;
+ dataPath.append("NumberElements/", -1, status);
+ dataPath.append(nsName, -1, status);
+ dataPath.append("/miscPatterns", -1, status);
+ if (U_FAILURE(status)) { return; }
+
+ UErrorCode localStatus = U_ZERO_ERROR;
+ ures_getAllItemsWithFallback(rb.getAlias(), dataPath.data(), sink, localStatus);
+ if (U_FAILURE(localStatus) && localStatus != U_MISSING_RESOURCE_ERROR) {
+ status = localStatus;
+ return;
+ }
+
+ // Fall back to latn if necessary
+ if (!sink.isComplete()) {
+ ures_getAllItemsWithFallback(rb.getAlias(), "NumberElements/latn/miscPatterns", sink, status);
+ }
+
+ sink.fillInDefaults(status);
+}
+
+class PluralRangesDataSink : public ResourceSink {
+ public:
+ PluralRangesDataSink(StandardPluralRanges& output) : fOutput(output) {}
+
+ void put(const char* /*key*/, ResourceValue& value, UBool /*noFallback*/, UErrorCode& status) U_OVERRIDE {
+ ResourceArray entriesArray = value.getArray(status);
+ if (U_FAILURE(status)) { return; }
+ fOutput.setCapacity(entriesArray.getSize());
+ for (int i = 0; entriesArray.getValue(i, value); i++) {
+ ResourceArray pluralFormsArray = value.getArray(status);
+ if (U_FAILURE(status)) { return; }
+ pluralFormsArray.getValue(0, value);
+ StandardPlural::Form first = StandardPlural::fromString(value.getUnicodeString(status), status);
+ if (U_FAILURE(status)) { return; }
+ pluralFormsArray.getValue(1, value);
+ StandardPlural::Form second = StandardPlural::fromString(value.getUnicodeString(status), status);
+ if (U_FAILURE(status)) { return; }
+ pluralFormsArray.getValue(2, value);
+ StandardPlural::Form result = StandardPlural::fromString(value.getUnicodeString(status), status);
+ if (U_FAILURE(status)) { return; }
+ fOutput.addPluralRange(first, second, result);
+ }
+ }
+
+ private:
+ StandardPluralRanges& fOutput;
+};
+
+void getPluralRangesData(const Locale& locale, StandardPluralRanges& output, UErrorCode& status) {
+ if (U_FAILURE(status)) { return; }
+ LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "pluralRanges", &status));
+ if (U_FAILURE(status)) { return; }
+
+ CharString dataPath;
+ dataPath.append("locales/", -1, status);
+ dataPath.append(locale.getLanguage(), -1, status);
+ if (U_FAILURE(status)) { return; }
+ int32_t setLen;
+ // Not all languages are covered: fail gracefully
+ UErrorCode internalStatus = U_ZERO_ERROR;
+ const UChar* set = ures_getStringByKeyWithFallback(rb.getAlias(), dataPath.data(), &setLen, &internalStatus);
+ if (U_FAILURE(internalStatus)) { return; }
+
+ dataPath.clear();
+ dataPath.append("rules/", -1, status);
+ dataPath.appendInvariantChars(set, setLen, status);
+ if (U_FAILURE(status)) { return; }
+ PluralRangesDataSink sink(output);
+ ures_getAllItemsWithFallback(rb.getAlias(), dataPath.data(), sink, status);
+ if (U_FAILURE(status)) { return; }
+}
+
+} // namespace
+
+
+void StandardPluralRanges::initialize(const Locale& locale, UErrorCode& status) {
+ getPluralRangesData(locale, *this, status);
+}
+
+void StandardPluralRanges::addPluralRange(
+ StandardPlural::Form first,
+ StandardPlural::Form second,
+ StandardPlural::Form result) {
+ U_ASSERT(fTriplesLen < fTriples.getCapacity());
+ fTriples[fTriplesLen] = {first, second, result};
+ fTriplesLen++;
+}
+
+void StandardPluralRanges::setCapacity(int32_t length) {
+ if (length > fTriples.getCapacity()) {
+ fTriples.resize(length, 0);
+ }
+}
+
+StandardPlural::Form
+StandardPluralRanges::resolve(StandardPlural::Form first, StandardPlural::Form second) const {
+ for (int32_t i=0; i<fTriplesLen; i++) {
+ const auto& triple = fTriples[i];
+ if (triple.first == first && triple.second == second) {
+ return triple.result;
+ }
+ }
+ // Default fallback
+ return StandardPlural::OTHER;
+}
+
+
+NumberRangeFormatterImpl::NumberRangeFormatterImpl(const RangeMacroProps& macros, UErrorCode& status)
+ : formatterImpl1(macros.formatter1.fMacros, status),
+ formatterImpl2(macros.formatter2.fMacros, status),
+ fSameFormatters(macros.singleFormatter),
+ fCollapse(macros.collapse),
+ fIdentityFallback(macros.identityFallback) {
+
+ const char* nsName = formatterImpl1.getRawMicroProps().nsName;
+ if (uprv_strcmp(nsName, formatterImpl2.getRawMicroProps().nsName) != 0) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ NumberRangeData data;
+ getNumberRangeData(macros.locale.getName(), nsName, data, status);
+ if (U_FAILURE(status)) { return; }
+ fRangeFormatter = data.rangePattern;
+ fApproximatelyModifier = {data.approximatelyPattern, kUndefinedField, false};
+
+ // TODO: Get locale from PluralRules instead?
+ fPluralRanges.initialize(macros.locale, status);
+ if (U_FAILURE(status)) { return; }
+}
+
+void NumberRangeFormatterImpl::format(UFormattedNumberRangeData& data, bool equalBeforeRounding, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ MicroProps micros1;
+ MicroProps micros2;
+ formatterImpl1.preProcess(data.quantity1, micros1, status);
+ if (fSameFormatters) {
+ formatterImpl1.preProcess(data.quantity2, micros2, status);
+ } else {
+ formatterImpl2.preProcess(data.quantity2, micros2, status);
+ }
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // If any of the affixes are different, an identity is not possible
+ // and we must use formatRange().
+ // TODO: Write this as MicroProps operator==() ?
+ // TODO: Avoid the redundancy of these equality operations with the
+ // ones in formatRange?
+ if (!micros1.modInner->semanticallyEquivalent(*micros2.modInner)
+ || !micros1.modMiddle->semanticallyEquivalent(*micros2.modMiddle)
+ || !micros1.modOuter->semanticallyEquivalent(*micros2.modOuter)) {
+ formatRange(data, micros1, micros2, status);
+ data.identityResult = UNUM_IDENTITY_RESULT_NOT_EQUAL;
+ return;
+ }
+
+ // Check for identity
+ if (equalBeforeRounding) {
+ data.identityResult = UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING;
+ } else if (data.quantity1 == data.quantity2) {
+ data.identityResult = UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING;
+ } else {
+ data.identityResult = UNUM_IDENTITY_RESULT_NOT_EQUAL;
+ }
+
+ switch (identity2d(fIdentityFallback, data.identityResult)) {
+ case identity2d(UNUM_IDENTITY_FALLBACK_RANGE,
+ UNUM_IDENTITY_RESULT_NOT_EQUAL):
+ case identity2d(UNUM_IDENTITY_FALLBACK_RANGE,
+ UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING):
+ case identity2d(UNUM_IDENTITY_FALLBACK_RANGE,
+ UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING):
+ case identity2d(UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
+ UNUM_IDENTITY_RESULT_NOT_EQUAL):
+ case identity2d(UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE,
+ UNUM_IDENTITY_RESULT_NOT_EQUAL):
+ case identity2d(UNUM_IDENTITY_FALLBACK_SINGLE_VALUE,
+ UNUM_IDENTITY_RESULT_NOT_EQUAL):
+ formatRange(data, micros1, micros2, status);
+ break;
+
+ case identity2d(UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
+ UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING):
+ case identity2d(UNUM_IDENTITY_FALLBACK_APPROXIMATELY,
+ UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING):
+ case identity2d(UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE,
+ UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING):
+ formatApproximately(data, micros1, micros2, status);
+ break;
+
+ case identity2d(UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE,
+ UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING):
+ case identity2d(UNUM_IDENTITY_FALLBACK_SINGLE_VALUE,
+ UNUM_IDENTITY_RESULT_EQUAL_AFTER_ROUNDING):
+ case identity2d(UNUM_IDENTITY_FALLBACK_SINGLE_VALUE,
+ UNUM_IDENTITY_RESULT_EQUAL_BEFORE_ROUNDING):
+ formatSingleValue(data, micros1, micros2, status);
+ break;
+
+ default:
+ UPRV_UNREACHABLE;
+ }
+}
+
+
+void NumberRangeFormatterImpl::formatSingleValue(UFormattedNumberRangeData& data,
+ MicroProps& micros1, MicroProps& micros2,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) { return; }
+ if (fSameFormatters) {
+ int32_t length = NumberFormatterImpl::writeNumber(micros1, data.quantity1, data.getStringRef(), 0, status);
+ NumberFormatterImpl::writeAffixes(micros1, data.getStringRef(), 0, length, status);
+ } else {
+ formatRange(data, micros1, micros2, status);
+ }
+}
+
+
+void NumberRangeFormatterImpl::formatApproximately (UFormattedNumberRangeData& data,
+ MicroProps& micros1, MicroProps& micros2,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) { return; }
+ if (fSameFormatters) {
+ int32_t length = NumberFormatterImpl::writeNumber(micros1, data.quantity1, data.getStringRef(), 0, status);
+ // HEURISTIC: Desired modifier order: inner, middle, approximately, outer.
+ length += micros1.modInner->apply(data.getStringRef(), 0, length, status);
+ length += micros1.modMiddle->apply(data.getStringRef(), 0, length, status);
+ length += fApproximatelyModifier.apply(data.getStringRef(), 0, length, status);
+ micros1.modOuter->apply(data.getStringRef(), 0, length, status);
+ } else {
+ formatRange(data, micros1, micros2, status);
+ }
+}
+
+
+void NumberRangeFormatterImpl::formatRange(UFormattedNumberRangeData& data,
+ MicroProps& micros1, MicroProps& micros2,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) { return; }
+
+ // modInner is always notation (scientific); collapsable in ALL.
+ // modOuter is always units; collapsable in ALL, AUTO, and UNIT.
+ // modMiddle could be either; collapsable in ALL and sometimes AUTO and UNIT.
+ // Never collapse an outer mod but not an inner mod.
+ bool collapseOuter, collapseMiddle, collapseInner;
+ switch (fCollapse) {
+ case UNUM_RANGE_COLLAPSE_ALL:
+ case UNUM_RANGE_COLLAPSE_AUTO:
+ case UNUM_RANGE_COLLAPSE_UNIT:
+ {
+ // OUTER MODIFIER
+ collapseOuter = micros1.modOuter->semanticallyEquivalent(*micros2.modOuter);
+
+ if (!collapseOuter) {
+ // Never collapse inner mods if outer mods are not collapsable
+ collapseMiddle = false;
+ collapseInner = false;
+ break;
+ }
+
+ // MIDDLE MODIFIER
+ collapseMiddle = micros1.modMiddle->semanticallyEquivalent(*micros2.modMiddle);
+
+ if (!collapseMiddle) {
+ // Never collapse inner mods if outer mods are not collapsable
+ collapseInner = false;
+ break;
+ }
+
+ // MIDDLE MODIFIER HEURISTICS
+ // (could disable collapsing of the middle modifier)
+ // The modifiers are equal by this point, so we can look at just one of them.
+ const Modifier* mm = micros1.modMiddle;
+ if (fCollapse == UNUM_RANGE_COLLAPSE_UNIT) {
+ // Only collapse if the modifier is a unit.
+ // TODO: Make a better way to check for a unit?
+ // TODO: Handle case where the modifier has both notation and unit (compact currency)?
+ if (!mm->containsField({UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD})
+ && !mm->containsField({UFIELD_CATEGORY_NUMBER, UNUM_PERCENT_FIELD})) {
+ collapseMiddle = false;
+ }
+ } else if (fCollapse == UNUM_RANGE_COLLAPSE_AUTO) {
+ // Heuristic as of ICU 63: collapse only if the modifier is more than one code point.
+ if (mm->getCodePointCount() <= 1) {
+ collapseMiddle = false;
+ }
+ }
+
+ if (!collapseMiddle || fCollapse != UNUM_RANGE_COLLAPSE_ALL) {
+ collapseInner = false;
+ break;
+ }
+
+ // INNER MODIFIER
+ collapseInner = micros1.modInner->semanticallyEquivalent(*micros2.modInner);
+
+ // All done checking for collapsability.
+ break;
+ }
+
+ default:
+ collapseOuter = false;
+ collapseMiddle = false;
+ collapseInner = false;
+ break;
+ }
+
+ FormattedStringBuilder& string = data.getStringRef();
+ int32_t lengthPrefix = 0;
+ int32_t length1 = 0;
+ int32_t lengthInfix = 0;
+ int32_t length2 = 0;
+ int32_t lengthSuffix = 0;
+
+ // Use #define so that these are evaluated at the call site.
+ #define UPRV_INDEX_0 (lengthPrefix)
+ #define UPRV_INDEX_1 (lengthPrefix + length1)
+ #define UPRV_INDEX_2 (lengthPrefix + length1 + lengthInfix)
+ #define UPRV_INDEX_3 (lengthPrefix + length1 + lengthInfix + length2)
+
+ int32_t lengthRange = SimpleModifier::formatTwoArgPattern(
+ fRangeFormatter,
+ string,
+ 0,
+ &lengthPrefix,
+ &lengthSuffix,
+ kUndefinedField,
+ status);
+ if (U_FAILURE(status)) { return; }
+ lengthInfix = lengthRange - lengthPrefix - lengthSuffix;
+ U_ASSERT(lengthInfix > 0);
+
+ // SPACING HEURISTIC
+ // Add spacing unless all modifiers are collapsed.
+ // TODO: add API to control this?
+ // TODO: Use a data-driven heuristic like currency spacing?
+ // TODO: Use Unicode [:whitespace:] instead of PatternProps whitespace? (consider speed implications)
+ {
+ bool repeatInner = !collapseInner && micros1.modInner->getCodePointCount() > 0;
+ bool repeatMiddle = !collapseMiddle && micros1.modMiddle->getCodePointCount() > 0;
+ bool repeatOuter = !collapseOuter && micros1.modOuter->getCodePointCount() > 0;
+ if (repeatInner || repeatMiddle || repeatOuter) {
+ // Add spacing if there is not already spacing
+ if (!PatternProps::isWhiteSpace(string.charAt(UPRV_INDEX_1))) {
+ lengthInfix += string.insertCodePoint(UPRV_INDEX_1, u'\u0020', kUndefinedField, status);
+ }
+ if (!PatternProps::isWhiteSpace(string.charAt(UPRV_INDEX_2 - 1))) {
+ lengthInfix += string.insertCodePoint(UPRV_INDEX_2, u'\u0020', kUndefinedField, status);
+ }
+ }
+ }
+
+ length1 += NumberFormatterImpl::writeNumber(micros1, data.quantity1, string, UPRV_INDEX_0, status);
+ length2 += NumberFormatterImpl::writeNumber(micros2, data.quantity2, string, UPRV_INDEX_2, status);
+
+ // TODO: Support padding?
+
+ if (collapseInner) {
+ // Note: this is actually a mix of prefix and suffix, but adding to infix length works
+ const Modifier& mod = resolveModifierPlurals(*micros1.modInner, *micros2.modInner);
+ lengthInfix += mod.apply(string, UPRV_INDEX_0, UPRV_INDEX_3, status);
+ } else {
+ length1 += micros1.modInner->apply(string, UPRV_INDEX_0, UPRV_INDEX_1, status);
+ length2 += micros2.modInner->apply(string, UPRV_INDEX_2, UPRV_INDEX_3, status);
+ }
+
+ if (collapseMiddle) {
+ // Note: this is actually a mix of prefix and suffix, but adding to infix length works
+ const Modifier& mod = resolveModifierPlurals(*micros1.modMiddle, *micros2.modMiddle);
+ lengthInfix += mod.apply(string, UPRV_INDEX_0, UPRV_INDEX_3, status);
+ } else {
+ length1 += micros1.modMiddle->apply(string, UPRV_INDEX_0, UPRV_INDEX_1, status);
+ length2 += micros2.modMiddle->apply(string, UPRV_INDEX_2, UPRV_INDEX_3, status);
+ }
+
+ if (collapseOuter) {
+ // Note: this is actually a mix of prefix and suffix, but adding to infix length works
+ const Modifier& mod = resolveModifierPlurals(*micros1.modOuter, *micros2.modOuter);
+ lengthInfix += mod.apply(string, UPRV_INDEX_0, UPRV_INDEX_3, status);
+ } else {
+ length1 += micros1.modOuter->apply(string, UPRV_INDEX_0, UPRV_INDEX_1, status);
+ length2 += micros2.modOuter->apply(string, UPRV_INDEX_2, UPRV_INDEX_3, status);
+ }
+}
+
+
+const Modifier&
+NumberRangeFormatterImpl::resolveModifierPlurals(const Modifier& first, const Modifier& second) const {
+ Modifier::Parameters parameters;
+ first.getParameters(parameters);
+ if (parameters.obj == nullptr) {
+ // No plural form; return a fallback (e.g., the first)
+ return first;
+ }
+ StandardPlural::Form firstPlural = parameters.plural;
+
+ second.getParameters(parameters);
+ if (parameters.obj == nullptr) {
+ // No plural form; return a fallback (e.g., the first)
+ return first;
+ }
+ StandardPlural::Form secondPlural = parameters.plural;
+
+ // Get the required plural form from data
+ StandardPlural::Form resultPlural = fPluralRanges.resolve(firstPlural, secondPlural);
+
+ // Get and return the new Modifier
+ const Modifier* mod = parameters.obj->getModifier(parameters.signum, resultPlural);
+ U_ASSERT(mod != nullptr);
+ return *mod;
+}
+
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/numrange_impl.h b/contrib/libs/icu/i18n/numrange_impl.h
index 8f4c8a40ba..de1f8848de 100644
--- a/contrib/libs/icu/i18n/numrange_impl.h
+++ b/contrib/libs/icu/i18n/numrange_impl.h
@@ -1,113 +1,113 @@
-// © 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_NUMRANGE_TYPES_H__
-#define __SOURCE_NUMRANGE_TYPES_H__
-
-#include "unicode/numberformatter.h"
-#include "unicode/numberrangeformatter.h"
-#include "unicode/simpleformatter.h"
-#include "number_types.h"
-#include "number_decimalquantity.h"
-#include "number_formatimpl.h"
-#include "formatted_string_builder.h"
-#include "formattedval_impl.h"
-
-U_NAMESPACE_BEGIN namespace number {
-namespace impl {
-
-
-/**
- * Class similar to UFormattedNumberData.
- *
- * Has incomplete magic number logic that will need to be finished
- * if this is to be exposed as C API in the future.
- *
- * Possible magic number: 0x46445200
- * Reads in ASCII as "FDR" (FormatteDnumberRange with room at the end)
- */
-class UFormattedNumberRangeData : public FormattedValueStringBuilderImpl {
-public:
- UFormattedNumberRangeData() : FormattedValueStringBuilderImpl(kUndefinedField) {}
- virtual ~UFormattedNumberRangeData();
-
- DecimalQuantity quantity1;
- DecimalQuantity quantity2;
- UNumberRangeIdentityResult identityResult = UNUM_IDENTITY_RESULT_COUNT;
-};
-
-
-class StandardPluralRanges : public UMemory {
- public:
- void initialize(const Locale& locale, UErrorCode& status);
- StandardPlural::Form resolve(StandardPlural::Form first, StandardPlural::Form second) const;
-
- /** Used for data loading. */
- void addPluralRange(
- StandardPlural::Form first,
- StandardPlural::Form second,
- StandardPlural::Form result);
-
- /** Used for data loading. */
- void setCapacity(int32_t length);
-
- private:
- struct StandardPluralRangeTriple {
- StandardPlural::Form first;
- StandardPlural::Form second;
- StandardPlural::Form result;
- };
-
- // TODO: An array is simple here, but it results in linear lookup time.
- // Certain locales have 20-30 entries in this list.
- // Consider changing to a smarter data structure.
- typedef MaybeStackArray<StandardPluralRangeTriple, 3> PluralRangeTriples;
- PluralRangeTriples fTriples;
- int32_t fTriplesLen = 0;
-};
-
-
-class NumberRangeFormatterImpl : public UMemory {
- public:
- NumberRangeFormatterImpl(const RangeMacroProps& macros, UErrorCode& status);
-
- void format(UFormattedNumberRangeData& data, bool equalBeforeRounding, UErrorCode& status) const;
-
- private:
- NumberFormatterImpl formatterImpl1;
- NumberFormatterImpl formatterImpl2;
- bool fSameFormatters;
-
- UNumberRangeCollapse fCollapse;
- UNumberRangeIdentityFallback fIdentityFallback;
-
- SimpleFormatter fRangeFormatter;
- SimpleModifier fApproximatelyModifier;
-
- StandardPluralRanges fPluralRanges;
-
- void formatSingleValue(UFormattedNumberRangeData& data,
- MicroProps& micros1, MicroProps& micros2,
- UErrorCode& status) const;
-
- void formatApproximately(UFormattedNumberRangeData& data,
- MicroProps& micros1, MicroProps& micros2,
- UErrorCode& status) const;
-
- void formatRange(UFormattedNumberRangeData& data,
- MicroProps& micros1, MicroProps& micros2,
- UErrorCode& status) const;
-
- const Modifier& resolveModifierPlurals(const Modifier& first, const Modifier& second) const;
-};
-
-
-} // namespace impl
-} // namespace number
-U_NAMESPACE_END
-
-#endif //__SOURCE_NUMRANGE_TYPES_H__
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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_NUMRANGE_TYPES_H__
+#define __SOURCE_NUMRANGE_TYPES_H__
+
+#include "unicode/numberformatter.h"
+#include "unicode/numberrangeformatter.h"
+#include "unicode/simpleformatter.h"
+#include "number_types.h"
+#include "number_decimalquantity.h"
+#include "number_formatimpl.h"
+#include "formatted_string_builder.h"
+#include "formattedval_impl.h"
+
+U_NAMESPACE_BEGIN namespace number {
+namespace impl {
+
+
+/**
+ * Class similar to UFormattedNumberData.
+ *
+ * Has incomplete magic number logic that will need to be finished
+ * if this is to be exposed as C API in the future.
+ *
+ * Possible magic number: 0x46445200
+ * Reads in ASCII as "FDR" (FormatteDnumberRange with room at the end)
+ */
+class UFormattedNumberRangeData : public FormattedValueStringBuilderImpl {
+public:
+ UFormattedNumberRangeData() : FormattedValueStringBuilderImpl(kUndefinedField) {}
+ virtual ~UFormattedNumberRangeData();
+
+ DecimalQuantity quantity1;
+ DecimalQuantity quantity2;
+ UNumberRangeIdentityResult identityResult = UNUM_IDENTITY_RESULT_COUNT;
+};
+
+
+class StandardPluralRanges : public UMemory {
+ public:
+ void initialize(const Locale& locale, UErrorCode& status);
+ StandardPlural::Form resolve(StandardPlural::Form first, StandardPlural::Form second) const;
+
+ /** Used for data loading. */
+ void addPluralRange(
+ StandardPlural::Form first,
+ StandardPlural::Form second,
+ StandardPlural::Form result);
+
+ /** Used for data loading. */
+ void setCapacity(int32_t length);
+
+ private:
+ struct StandardPluralRangeTriple {
+ StandardPlural::Form first;
+ StandardPlural::Form second;
+ StandardPlural::Form result;
+ };
+
+ // TODO: An array is simple here, but it results in linear lookup time.
+ // Certain locales have 20-30 entries in this list.
+ // Consider changing to a smarter data structure.
+ typedef MaybeStackArray<StandardPluralRangeTriple, 3> PluralRangeTriples;
+ PluralRangeTriples fTriples;
+ int32_t fTriplesLen = 0;
+};
+
+
+class NumberRangeFormatterImpl : public UMemory {
+ public:
+ NumberRangeFormatterImpl(const RangeMacroProps& macros, UErrorCode& status);
+
+ void format(UFormattedNumberRangeData& data, bool equalBeforeRounding, UErrorCode& status) const;
+
+ private:
+ NumberFormatterImpl formatterImpl1;
+ NumberFormatterImpl formatterImpl2;
+ bool fSameFormatters;
+
+ UNumberRangeCollapse fCollapse;
+ UNumberRangeIdentityFallback fIdentityFallback;
+
+ SimpleFormatter fRangeFormatter;
+ SimpleModifier fApproximatelyModifier;
+
+ StandardPluralRanges fPluralRanges;
+
+ void formatSingleValue(UFormattedNumberRangeData& data,
+ MicroProps& micros1, MicroProps& micros2,
+ UErrorCode& status) const;
+
+ void formatApproximately(UFormattedNumberRangeData& data,
+ MicroProps& micros1, MicroProps& micros2,
+ UErrorCode& status) const;
+
+ void formatRange(UFormattedNumberRangeData& data,
+ MicroProps& micros1, MicroProps& micros2,
+ UErrorCode& status) const;
+
+ const Modifier& resolveModifierPlurals(const Modifier& first, const Modifier& second) const;
+};
+
+
+} // namespace impl
+} // namespace number
+U_NAMESPACE_END
+
+#endif //__SOURCE_NUMRANGE_TYPES_H__
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/numsys.cpp b/contrib/libs/icu/i18n/numsys.cpp
index 62d555aad2..aaae821e98 100644
--- a/contrib/libs/icu/i18n/numsys.cpp
+++ b/contrib/libs/icu/i18n/numsys.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -25,9 +25,9 @@
#include "unicode/schriter.h"
#include "unicode/numsys.h"
#include "cstring.h"
-#include "uassert.h"
-#include "ucln_in.h"
-#include "umutex.h"
+#include "uassert.h"
+#include "ucln_in.h"
+#include "umutex.h"
#include "uresimp.h"
#include "numsys_impl.h"
@@ -37,7 +37,7 @@ U_NAMESPACE_BEGIN
// Useful constants
-#define DEFAULT_DIGITS UNICODE_STRING_SIMPLE("0123456789")
+#define DEFAULT_DIGITS UNICODE_STRING_SIMPLE("0123456789")
static const char gNumberingSystems[] = "numberingSystems";
static const char gNumberElements[] = "NumberElements";
static const char gDefault[] = "default";
@@ -81,82 +81,82 @@ NumberingSystem* U_EXPORT2
NumberingSystem::createInstance(int32_t radix_in, UBool isAlgorithmic_in, const UnicodeString & desc_in, UErrorCode &status) {
if (U_FAILURE(status)) {
- return nullptr;
+ return nullptr;
}
if ( radix_in < 2 ) {
status = U_ILLEGAL_ARGUMENT_ERROR;
- return nullptr;
+ return nullptr;
}
if ( !isAlgorithmic_in ) {
if ( desc_in.countChar32() != radix_in ) {
status = U_ILLEGAL_ARGUMENT_ERROR;
- return nullptr;
+ return nullptr;
}
}
- LocalPointer<NumberingSystem> ns(new NumberingSystem(), status);
- if (U_FAILURE(status)) {
- return nullptr;
- }
+ LocalPointer<NumberingSystem> ns(new NumberingSystem(), status);
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
ns->setRadix(radix_in);
ns->setDesc(desc_in);
ns->setAlgorithmic(isAlgorithmic_in);
- ns->setName(nullptr);
-
- return ns.orphan();
+ ns->setName(nullptr);
+
+ return ns.orphan();
}
NumberingSystem* U_EXPORT2
NumberingSystem::createInstance(const Locale & inLocale, UErrorCode& status) {
if (U_FAILURE(status)) {
- return nullptr;
+ return nullptr;
}
UBool nsResolved = TRUE;
UBool usingFallback = FALSE;
- char buffer[ULOC_KEYWORDS_CAPACITY] = "";
- int32_t count = inLocale.getKeywordValue("numbers", buffer, sizeof(buffer), status);
- if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
- // the "numbers" keyword exceeds ULOC_KEYWORDS_CAPACITY; ignore and use default.
- count = 0;
- status = U_ZERO_ERROR;
- }
+ char buffer[ULOC_KEYWORDS_CAPACITY] = "";
+ int32_t count = inLocale.getKeywordValue("numbers", buffer, sizeof(buffer), status);
+ if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
+ // the "numbers" keyword exceeds ULOC_KEYWORDS_CAPACITY; ignore and use default.
+ count = 0;
+ status = U_ZERO_ERROR;
+ }
if ( count > 0 ) { // @numbers keyword was specified in the locale
- U_ASSERT(count < ULOC_KEYWORDS_CAPACITY);
+ U_ASSERT(count < ULOC_KEYWORDS_CAPACITY);
buffer[count] = '\0'; // Make sure it is null terminated.
if ( !uprv_strcmp(buffer,gDefault) || !uprv_strcmp(buffer,gNative) ||
!uprv_strcmp(buffer,gTraditional) || !uprv_strcmp(buffer,gFinance)) {
nsResolved = FALSE;
}
} else {
- uprv_strcpy(buffer, gDefault);
+ uprv_strcpy(buffer, gDefault);
nsResolved = FALSE;
}
if (!nsResolved) { // Resolve the numbering system ( default, native, traditional or finance ) into a "real" numbering system
UErrorCode localStatus = U_ZERO_ERROR;
- LocalUResourceBundlePointer resource(ures_open(nullptr, inLocale.getName(), &localStatus));
- LocalUResourceBundlePointer numberElementsRes(ures_getByKey(resource.getAlias(), gNumberElements, nullptr, &localStatus));
- // Don't stomp on the catastrophic failure of OOM.
- if (localStatus == U_MEMORY_ALLOCATION_ERROR) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
+ LocalUResourceBundlePointer resource(ures_open(nullptr, inLocale.getName(), &localStatus));
+ LocalUResourceBundlePointer numberElementsRes(ures_getByKey(resource.getAlias(), gNumberElements, nullptr, &localStatus));
+ // Don't stomp on the catastrophic failure of OOM.
+ if (localStatus == U_MEMORY_ALLOCATION_ERROR) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
while (!nsResolved) {
localStatus = U_ZERO_ERROR;
count = 0;
- const UChar *nsName = ures_getStringByKeyWithFallback(numberElementsRes.getAlias(), buffer, &count, &localStatus);
- // Don't stomp on the catastrophic failure of OOM.
- if (localStatus == U_MEMORY_ALLOCATION_ERROR) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
+ const UChar *nsName = ures_getStringByKeyWithFallback(numberElementsRes.getAlias(), buffer, &count, &localStatus);
+ // Don't stomp on the catastrophic failure of OOM.
+ if (localStatus == U_MEMORY_ALLOCATION_ERROR) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
if ( count > 0 && count < ULOC_KEYWORDS_CAPACITY ) { // numbering system found
- u_UCharsToChars(nsName, buffer, count);
+ u_UCharsToChars(nsName, buffer, count);
buffer[count] = '\0'; // Make sure it is null terminated.
nsResolved = TRUE;
}
@@ -177,12 +177,12 @@ NumberingSystem::createInstance(const Locale & inLocale, UErrorCode& status) {
if (usingFallback) {
status = U_USING_FALLBACK_WARNING;
NumberingSystem *ns = new NumberingSystem();
- if (ns == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
+ if (ns == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
return ns;
} else {
- return NumberingSystem::createInstanceByName(buffer, status);
+ return NumberingSystem::createInstanceByName(buffer, status);
}
}
@@ -196,34 +196,34 @@ NumberingSystem::createInstanceByName(const char *name, UErrorCode& status) {
int32_t radix = 10;
int32_t algorithmic = 0;
- LocalUResourceBundlePointer numberingSystemsInfo(ures_openDirect(nullptr, gNumberingSystems, &status));
- LocalUResourceBundlePointer nsCurrent(ures_getByKey(numberingSystemsInfo.getAlias(), gNumberingSystems, nullptr, &status));
- LocalUResourceBundlePointer nsTop(ures_getByKey(nsCurrent.getAlias(), name, nullptr, &status));
-
- UnicodeString nsd = ures_getUnicodeStringByKey(nsTop.getAlias(), gDesc, &status);
+ LocalUResourceBundlePointer numberingSystemsInfo(ures_openDirect(nullptr, gNumberingSystems, &status));
+ LocalUResourceBundlePointer nsCurrent(ures_getByKey(numberingSystemsInfo.getAlias(), gNumberingSystems, nullptr, &status));
+ LocalUResourceBundlePointer nsTop(ures_getByKey(nsCurrent.getAlias(), name, nullptr, &status));
- ures_getByKey(nsTop.getAlias(), gRadix, nsCurrent.getAlias(), &status);
- radix = ures_getInt(nsCurrent.getAlias(), &status);
+ UnicodeString nsd = ures_getUnicodeStringByKey(nsTop.getAlias(), gDesc, &status);
- ures_getByKey(nsTop.getAlias(), gAlgorithmic, nsCurrent.getAlias(), &status);
- algorithmic = ures_getInt(nsCurrent.getAlias(), &status);
+ ures_getByKey(nsTop.getAlias(), gRadix, nsCurrent.getAlias(), &status);
+ radix = ures_getInt(nsCurrent.getAlias(), &status);
+ ures_getByKey(nsTop.getAlias(), gAlgorithmic, nsCurrent.getAlias(), &status);
+ algorithmic = ures_getInt(nsCurrent.getAlias(), &status);
+
UBool isAlgorithmic = ( algorithmic == 1 );
- if (U_FAILURE(status)) {
- // Don't stomp on the catastrophic failure of OOM.
- if (status != U_MEMORY_ALLOCATION_ERROR) {
- status = U_UNSUPPORTED_ERROR;
- }
- return nullptr;
- }
+ if (U_FAILURE(status)) {
+ // Don't stomp on the catastrophic failure of OOM.
+ if (status != U_MEMORY_ALLOCATION_ERROR) {
+ status = U_UNSUPPORTED_ERROR;
+ }
+ return nullptr;
+ }
- LocalPointer<NumberingSystem> ns(NumberingSystem::createInstance(radix, isAlgorithmic, nsd, status), status);
+ LocalPointer<NumberingSystem> ns(NumberingSystem::createInstance(radix, isAlgorithmic, nsd, status), status);
if (U_FAILURE(status)) {
- return nullptr;
+ return nullptr;
}
ns->setName(name);
- return ns.orphan();
+ return ns.orphan();
}
/**
@@ -253,99 +253,99 @@ void NumberingSystem::setAlgorithmic(UBool c) {
algorithmic = c;
}
-void NumberingSystem::setDesc(const UnicodeString &d) {
+void NumberingSystem::setDesc(const UnicodeString &d) {
desc.setTo(d);
}
void NumberingSystem::setName(const char *n) {
- if ( n == nullptr ) {
+ if ( n == nullptr ) {
name[0] = (char) 0;
} else {
- uprv_strncpy(name,n,kInternalNumSysNameCapacity);
- name[kInternalNumSysNameCapacity] = '\0'; // Make sure it is null terminated.
+ uprv_strncpy(name,n,kInternalNumSysNameCapacity);
+ name[kInternalNumSysNameCapacity] = '\0'; // Make sure it is null terminated.
}
}
UBool NumberingSystem::isAlgorithmic() const {
return ( algorithmic );
}
-namespace {
-
-UVector* gNumsysNames = nullptr;
-UInitOnce gNumSysInitOnce = U_INITONCE_INITIALIZER;
-
-U_CFUNC UBool U_CALLCONV numSysCleanup() {
- delete gNumsysNames;
- gNumsysNames = nullptr;
- gNumSysInitOnce.reset();
- return true;
-}
-
-U_CFUNC void initNumsysNames(UErrorCode &status) {
- U_ASSERT(gNumsysNames == nullptr);
- ucln_i18n_registerCleanup(UCLN_I18N_NUMSYS, numSysCleanup);
-
- // TODO: Simple array of UnicodeString objects, based on length of table resource?
- LocalPointer<UVector> numsysNames(new UVector(uprv_deleteUObject, nullptr, status), status);
+namespace {
+
+UVector* gNumsysNames = nullptr;
+UInitOnce gNumSysInitOnce = U_INITONCE_INITIALIZER;
+
+U_CFUNC UBool U_CALLCONV numSysCleanup() {
+ delete gNumsysNames;
+ gNumsysNames = nullptr;
+ gNumSysInitOnce.reset();
+ return true;
+}
+
+U_CFUNC void initNumsysNames(UErrorCode &status) {
+ U_ASSERT(gNumsysNames == nullptr);
+ ucln_i18n_registerCleanup(UCLN_I18N_NUMSYS, numSysCleanup);
+
+ // TODO: Simple array of UnicodeString objects, based on length of table resource?
+ LocalPointer<UVector> numsysNames(new UVector(uprv_deleteUObject, nullptr, status), status);
if (U_FAILURE(status)) {
- return;
+ return;
}
- UErrorCode rbstatus = U_ZERO_ERROR;
- UResourceBundle *numberingSystemsInfo = ures_openDirect(nullptr, "numberingSystems", &rbstatus);
- numberingSystemsInfo =
- ures_getByKey(numberingSystemsInfo, "numberingSystems", numberingSystemsInfo, &rbstatus);
- if (U_FAILURE(rbstatus)) {
- // Don't stomp on the catastrophic failure of OOM.
- if (rbstatus == U_MEMORY_ALLOCATION_ERROR) {
- status = rbstatus;
- } else {
+ UErrorCode rbstatus = U_ZERO_ERROR;
+ UResourceBundle *numberingSystemsInfo = ures_openDirect(nullptr, "numberingSystems", &rbstatus);
+ numberingSystemsInfo =
+ ures_getByKey(numberingSystemsInfo, "numberingSystems", numberingSystemsInfo, &rbstatus);
+ if (U_FAILURE(rbstatus)) {
+ // Don't stomp on the catastrophic failure of OOM.
+ if (rbstatus == U_MEMORY_ALLOCATION_ERROR) {
+ status = rbstatus;
+ } else {
status = U_MISSING_RESOURCE_ERROR;
}
- ures_close(numberingSystemsInfo);
- return;
- }
-
- while ( ures_hasNext(numberingSystemsInfo) && U_SUCCESS(status) ) {
- LocalUResourceBundlePointer nsCurrent(ures_getNextResource(numberingSystemsInfo, nullptr, &rbstatus));
- if (rbstatus == U_MEMORY_ALLOCATION_ERROR) {
- status = rbstatus; // we want to report OOM failure back to the caller.
- break;
+ ures_close(numberingSystemsInfo);
+ return;
+ }
+
+ while ( ures_hasNext(numberingSystemsInfo) && U_SUCCESS(status) ) {
+ LocalUResourceBundlePointer nsCurrent(ures_getNextResource(numberingSystemsInfo, nullptr, &rbstatus));
+ if (rbstatus == U_MEMORY_ALLOCATION_ERROR) {
+ status = rbstatus; // we want to report OOM failure back to the caller.
+ break;
}
- const char *nsName = ures_getKey(nsCurrent.getAlias());
- LocalPointer<UnicodeString> newElem(new UnicodeString(nsName, -1, US_INV), status);
- if (U_SUCCESS(status)) {
- numsysNames->addElement(newElem.getAlias(), status);
- if (U_SUCCESS(status)) {
- newElem.orphan(); // on success, the numsysNames vector owns newElem.
- }
+ const char *nsName = ures_getKey(nsCurrent.getAlias());
+ LocalPointer<UnicodeString> newElem(new UnicodeString(nsName, -1, US_INV), status);
+ if (U_SUCCESS(status)) {
+ numsysNames->addElement(newElem.getAlias(), status);
+ if (U_SUCCESS(status)) {
+ newElem.orphan(); // on success, the numsysNames vector owns newElem.
+ }
}
}
- ures_close(numberingSystemsInfo);
- if (U_SUCCESS(status)) {
- gNumsysNames = numsysNames.orphan();
- }
- return;
-}
-
-} // end anonymous namespace
-
-StringEnumeration* NumberingSystem::getAvailableNames(UErrorCode &status) {
- umtx_initOnce(gNumSysInitOnce, &initNumsysNames, status);
- LocalPointer<StringEnumeration> result(new NumsysNameEnumeration(status), status);
- return result.orphan();
+ ures_close(numberingSystemsInfo);
+ if (U_SUCCESS(status)) {
+ gNumsysNames = numsysNames.orphan();
+ }
+ return;
}
-NumsysNameEnumeration::NumsysNameEnumeration(UErrorCode& status) : pos(0) {
- (void)status;
+} // end anonymous namespace
+
+StringEnumeration* NumberingSystem::getAvailableNames(UErrorCode &status) {
+ umtx_initOnce(gNumSysInitOnce, &initNumsysNames, status);
+ LocalPointer<StringEnumeration> result(new NumsysNameEnumeration(status), status);
+ return result.orphan();
}
+NumsysNameEnumeration::NumsysNameEnumeration(UErrorCode& status) : pos(0) {
+ (void)status;
+}
+
const UnicodeString*
NumsysNameEnumeration::snext(UErrorCode& status) {
- if (U_SUCCESS(status) && (gNumsysNames != nullptr) && (pos < gNumsysNames->size())) {
- return (const UnicodeString*)gNumsysNames->elementAt(pos++);
+ if (U_SUCCESS(status) && (gNumsysNames != nullptr) && (pos < gNumsysNames->size())) {
+ return (const UnicodeString*)gNumsysNames->elementAt(pos++);
}
- return nullptr;
+ return nullptr;
}
void
@@ -355,7 +355,7 @@ NumsysNameEnumeration::reset(UErrorCode& /*status*/) {
int32_t
NumsysNameEnumeration::count(UErrorCode& /*status*/) const {
- return (gNumsysNames==nullptr) ? 0 : gNumsysNames->size();
+ return (gNumsysNames==nullptr) ? 0 : gNumsysNames->size();
}
NumsysNameEnumeration::~NumsysNameEnumeration() {
diff --git a/contrib/libs/icu/i18n/numsys_impl.h b/contrib/libs/icu/i18n/numsys_impl.h
index e76e634dd2..e47b0c73fe 100644
--- a/contrib/libs/icu/i18n/numsys_impl.h
+++ b/contrib/libs/icu/i18n/numsys_impl.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -26,14 +26,14 @@ U_NAMESPACE_BEGIN
class NumsysNameEnumeration : public StringEnumeration {
public:
- NumsysNameEnumeration(UErrorCode& status);
+ NumsysNameEnumeration(UErrorCode& status);
virtual ~NumsysNameEnumeration();
static UClassID U_EXPORT2 getStaticClassID(void);
- virtual UClassID getDynamicClassID(void) const override;
- virtual const UnicodeString* snext(UErrorCode& status) override;
- virtual void reset(UErrorCode& status) override;
- virtual int32_t count(UErrorCode& status) const override;
+ virtual UClassID getDynamicClassID(void) const override;
+ virtual const UnicodeString* snext(UErrorCode& status) override;
+ virtual void reset(UErrorCode& status) override;
+ virtual int32_t count(UErrorCode& status) const override;
private:
int32_t pos;
};
diff --git a/contrib/libs/icu/i18n/olsontz.cpp b/contrib/libs/icu/i18n/olsontz.cpp
index d21e6e9929..eb7b91bb6e 100644
--- a/contrib/libs/icu/i18n/olsontz.cpp
+++ b/contrib/libs/icu/i18n/olsontz.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -25,7 +25,7 @@
#include "uassert.h"
#include "uvector.h"
#include <float.h> // DBL_MAX
-#include "uresimp.h"
+#include "uresimp.h"
#include "zonemeta.h"
#include "umutex.h"
@@ -134,12 +134,12 @@ OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
// setID(ures_getKey((UResourceBundle*) res)); // cast away const
int32_t len;
- StackUResourceBundle r;
+ StackUResourceBundle r;
// Pre-32bit second transitions
- ures_getByKey(res, kTRANSPRE32, r.getAlias(), &ec);
- transitionTimesPre32 = ures_getIntVector(r.getAlias(), &len, &ec);
- transitionCountPre32 = static_cast<int16_t>(len >> 1);
+ ures_getByKey(res, kTRANSPRE32, r.getAlias(), &ec);
+ transitionTimesPre32 = ures_getIntVector(r.getAlias(), &len, &ec);
+ transitionCountPre32 = static_cast<int16_t>(len >> 1);
if (ec == U_MISSING_RESOURCE_ERROR) {
// No pre-32bit transitions
transitionTimesPre32 = NULL;
@@ -150,9 +150,9 @@ OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
}
// 32bit second transitions
- ures_getByKey(res, kTRANS, r.getAlias(), &ec);
- transitionTimes32 = ures_getIntVector(r.getAlias(), &len, &ec);
- transitionCount32 = static_cast<int16_t>(len);
+ ures_getByKey(res, kTRANS, r.getAlias(), &ec);
+ transitionTimes32 = ures_getIntVector(r.getAlias(), &len, &ec);
+ transitionCount32 = static_cast<int16_t>(len);
if (ec == U_MISSING_RESOURCE_ERROR) {
// No 32bit transitions
transitionTimes32 = NULL;
@@ -163,9 +163,9 @@ OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
}
// Post-32bit second transitions
- ures_getByKey(res, kTRANSPOST32, r.getAlias(), &ec);
- transitionTimesPost32 = ures_getIntVector(r.getAlias(), &len, &ec);
- transitionCountPost32 = static_cast<int16_t>(len >> 1);
+ ures_getByKey(res, kTRANSPOST32, r.getAlias(), &ec);
+ transitionTimesPost32 = ures_getIntVector(r.getAlias(), &len, &ec);
+ transitionCountPost32 = static_cast<int16_t>(len >> 1);
if (ec == U_MISSING_RESOURCE_ERROR) {
// No pre-32bit transitions
transitionTimesPost32 = NULL;
@@ -176,8 +176,8 @@ OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
}
// Type offsets list must be of even size, with size >= 2
- ures_getByKey(res, kTYPEOFFSETS, r.getAlias(), &ec);
- typeOffsets = ures_getIntVector(r.getAlias(), &len, &ec);
+ ures_getByKey(res, kTYPEOFFSETS, r.getAlias(), &ec);
+ typeOffsets = ures_getIntVector(r.getAlias(), &len, &ec);
if (U_SUCCESS(ec) && (len < 2 || len > 0x7FFE || (len & 1) != 0)) {
ec = U_INVALID_FORMAT_ERROR;
}
@@ -186,8 +186,8 @@ OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
// Type map data must be of the same size as the transition count
typeMapData = NULL;
if (transitionCount() > 0) {
- ures_getByKey(res, kTYPEMAP, r.getAlias(), &ec);
- typeMapData = ures_getBinary(r.getAlias(), &len, &ec);
+ ures_getByKey(res, kTYPEMAP, r.getAlias(), &ec);
+ typeMapData = ures_getBinary(r.getAlias(), &len, &ec);
if (ec == U_MISSING_RESOURCE_ERROR) {
// no type mapping data
ec = U_INVALID_FORMAT_ERROR;
@@ -198,10 +198,10 @@ OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
// Process final rule and data, if any
const UChar *ruleIdUStr = ures_getStringByKey(res, kFINALRULE, &len, &ec);
- ures_getByKey(res, kFINALRAW, r.getAlias(), &ec);
- int32_t ruleRaw = ures_getInt(r.getAlias(), &ec);
- ures_getByKey(res, kFINALYEAR, r.getAlias(), &ec);
- int32_t ruleYear = ures_getInt(r.getAlias(), &ec);
+ ures_getByKey(res, kFINALRAW, r.getAlias(), &ec);
+ int32_t ruleRaw = ures_getInt(r.getAlias(), &ec);
+ ures_getByKey(res, kFINALYEAR, r.getAlias(), &ec);
+ int32_t ruleYear = ures_getInt(r.getAlias(), &ec);
if (U_SUCCESS(ec)) {
UnicodeString ruleID(TRUE, ruleIdUStr, len);
UResourceBundle *rule = TimeZone::loadRule(top, ruleID, NULL, ec);
@@ -287,7 +287,7 @@ OlsonTimeZone& OlsonTimeZone::operator=(const OlsonTimeZone& other) {
typeMapData = other.typeMapData;
delete finalZone;
- finalZone = (other.finalZone != 0) ? other.finalZone->clone() : 0;
+ finalZone = (other.finalZone != 0) ? other.finalZone->clone() : 0;
finalStartYear = other.finalStartYear;
finalStartMillis = other.finalStartMillis;
@@ -318,7 +318,7 @@ UBool OlsonTimeZone::operator==(const TimeZone& other) const {
/**
* TimeZone API.
*/
-OlsonTimeZone* OlsonTimeZone::clone() const {
+OlsonTimeZone* OlsonTimeZone::clone() const {
return new OlsonTimeZone(*this);
}
@@ -815,7 +815,7 @@ OlsonTimeZone::initTransitionRules(UErrorCode& status) {
* For now, we do not set the valid start year when the construction time
* and create a clone and set the start year when extracting rules.
*/
- finalZoneWithStartYear = finalZone->clone();
+ finalZoneWithStartYear = finalZone->clone();
// Check to make sure finalZone was actually cloned.
if (finalZoneWithStartYear == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
@@ -836,7 +836,7 @@ OlsonTimeZone::initTransitionRules(UErrorCode& status) {
startTime = tzt.getTime();
} else {
// final rule with no transitions
- finalZoneWithStartYear = finalZone->clone();
+ finalZoneWithStartYear = finalZone->clone();
// Check to make sure finalZone was actually cloned.
if (finalZoneWithStartYear == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
diff --git a/contrib/libs/icu/i18n/olsontz.h b/contrib/libs/icu/i18n/olsontz.h
index a3b7dcc8f3..3884e9b15a 100644
--- a/contrib/libs/icu/i18n/olsontz.h
+++ b/contrib/libs/icu/i18n/olsontz.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -151,7 +151,7 @@ class U_I18N_API OlsonTimeZone: public BasicTimeZone {
/**
* TimeZone API.
*/
- virtual OlsonTimeZone* clone() const;
+ virtual OlsonTimeZone* clone() const;
/**
* TimeZone API.
@@ -398,7 +398,7 @@ private:
TimeArrayTimeZoneRule **historicRules;
int16_t historicRuleCount;
SimpleTimeZone *finalZoneWithStartYear; // hack
- UInitOnce transitionRulesInitOnce = U_INITONCE_INITIALIZER;
+ UInitOnce transitionRulesInitOnce = U_INITONCE_INITIALIZER;
};
inline int16_t
diff --git a/contrib/libs/icu/i18n/persncal.cpp b/contrib/libs/icu/i18n/persncal.cpp
index 26fd294cee..553377641b 100644
--- a/contrib/libs/icu/i18n/persncal.cpp
+++ b/contrib/libs/icu/i18n/persncal.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
@@ -74,7 +74,7 @@ const char *PersianCalendar::getType() const {
return "persian";
}
-PersianCalendar* PersianCalendar::clone() const {
+PersianCalendar* PersianCalendar::clone() const {
return new PersianCalendar(*this);
}
@@ -213,7 +213,7 @@ void PersianCalendar::handleComputeFields(int32_t julianDay, UErrorCode &/*statu
int32_t year, month, dayOfMonth, dayOfYear;
int32_t daysSinceEpoch = julianDay - PERSIAN_EPOCH;
- year = 1 + (int32_t)ClockMath::floorDivide(33 * (int64_t)daysSinceEpoch + 3, (int64_t)12053);
+ year = 1 + (int32_t)ClockMath::floorDivide(33 * (int64_t)daysSinceEpoch + 3, (int64_t)12053);
int32_t farvardin1 = 365 * (year - 1) + ClockMath::floorDivide(8 * year + 21, 33);
dayOfYear = (daysSinceEpoch - farvardin1); // 0-based
diff --git a/contrib/libs/icu/i18n/persncal.h b/contrib/libs/icu/i18n/persncal.h
index ce6d7397bf..d1dc710171 100644
--- a/contrib/libs/icu/i18n/persncal.h
+++ b/contrib/libs/icu/i18n/persncal.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
@@ -164,7 +164,7 @@ class PersianCalendar : public Calendar {
// TODO: copy c'tor, etc
// clone
- virtual PersianCalendar* clone() const;
+ virtual PersianCalendar* clone() const;
private:
/**
diff --git a/contrib/libs/icu/i18n/plurfmt.cpp b/contrib/libs/icu/i18n/plurfmt.cpp
index b99437630e..a802e3606a 100644
--- a/contrib/libs/icu/i18n/plurfmt.cpp
+++ b/contrib/libs/icu/i18n/plurfmt.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -21,16 +21,16 @@
#include "plurrule_impl.h"
#include "uassert.h"
#include "uhash.h"
-#include "number_decimalquantity.h"
-#include "number_utils.h"
-#include "number_utypes.h"
+#include "number_decimalquantity.h"
+#include "number_utils.h"
+#include "number_utypes.h"
#if !UCONFIG_NO_FORMATTING
U_NAMESPACE_BEGIN
-using number::impl::DecimalQuantity;
-
+using number::impl::DecimalQuantity;
+
static const UChar OTHER_STRING[] = {
0x6F, 0x74, 0x68, 0x65, 0x72, 0 // "other"
};
@@ -159,7 +159,7 @@ PluralFormat::copyObjects(const PluralFormat& other) {
if (other.numberFormat == NULL) {
numberFormat = NumberFormat::createInstance(locale, status);
} else {
- numberFormat = other.numberFormat->clone();
+ numberFormat = other.numberFormat->clone();
}
if (other.pluralRulesWrapper.pluralRules == NULL) {
pluralRulesWrapper.pluralRules = PluralRules::forLocale(locale, status);
@@ -261,40 +261,40 @@ 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;
- // 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) {
- // could be BigDecimal etc.
- numberObject.populateDecimalQuantity(data.quantity, status);
- } else {
- data.quantity.setToDouble(numberMinusOffset);
- }
+ // 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) {
+ // could be BigDecimal etc.
+ numberObject.populateDecimalQuantity(data.quantity, status);
+ } else {
+ data.quantity.setToDouble(numberMinusOffset);
+ }
UnicodeString numberString;
- auto *decFmt = dynamic_cast<DecimalFormat *>(numberFormat);
- if(decFmt != nullptr) {
- const number::LocalizedNumberFormatter* lnf = decFmt->toNumberFormatter(status);
- if (U_FAILURE(status)) {
- return appendTo;
- }
- lnf->formatImpl(&data, status); // mutates &data
- if (U_FAILURE(status)) {
- return appendTo;
+ auto *decFmt = dynamic_cast<DecimalFormat *>(numberFormat);
+ if(decFmt != nullptr) {
+ const number::LocalizedNumberFormatter* lnf = decFmt->toNumberFormatter(status);
+ if (U_FAILURE(status)) {
+ return appendTo;
}
- numberString = data.getStringRef().toUnicodeString();
+ lnf->formatImpl(&data, status); // mutates &data
+ if (U_FAILURE(status)) {
+ return appendTo;
+ }
+ numberString = data.getStringRef().toUnicodeString();
} else {
- if (offset == 0) {
- numberFormat->format(numberObject, numberString, status);
+ if (offset == 0) {
+ numberFormat->format(numberObject, numberString, status);
} else {
- numberFormat->format(numberMinusOffset, numberString, status);
+ numberFormat->format(numberMinusOffset, numberString, status);
}
}
-
- int32_t partIndex = findSubMessage(msgPattern, 0, pluralRulesWrapper, &data.quantity, 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.
@@ -353,7 +353,7 @@ PluralFormat::setNumberFormat(const NumberFormat* format, UErrorCode& status) {
if (U_FAILURE(status)) {
return;
}
- NumberFormat* nf = format->clone();
+ NumberFormat* nf = format->clone();
if (nf != NULL) {
delete numberFormat;
numberFormat = nf;
@@ -362,7 +362,7 @@ PluralFormat::setNumberFormat(const NumberFormat* format, UErrorCode& status) {
}
}
-PluralFormat*
+PluralFormat*
PluralFormat::clone() const
{
return new PluralFormat(*this);
@@ -583,7 +583,7 @@ PluralFormat::PluralSelectorAdapter::~PluralSelectorAdapter() {
UnicodeString PluralFormat::PluralSelectorAdapter::select(void *context, double number,
UErrorCode& /*ec*/) const {
(void)number; // unused except in the assertion
- IFixedDecimal *dec=static_cast<IFixedDecimal *>(context);
+ IFixedDecimal *dec=static_cast<IFixedDecimal *>(context);
return pluralRules->select(*dec);
}
diff --git a/contrib/libs/icu/i18n/plurrule.cpp b/contrib/libs/icu/i18n/plurrule.cpp
index 794a3d8c55..f21c622a33 100644
--- a/contrib/libs/icu/i18n/plurrule.cpp
+++ b/contrib/libs/icu/i18n/plurrule.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -17,8 +17,8 @@
#include "unicode/plurrule.h"
#include "unicode/upluralrules.h"
#include "unicode/ures.h"
-#include "unicode/numfmt.h"
-#include "unicode/decimfmt.h"
+#include "unicode/numfmt.h"
+#include "unicode/decimfmt.h"
#include "charstr.h"
#include "cmemory.h"
#include "cstring.h"
@@ -34,16 +34,16 @@
#include "uvectr32.h"
#include "sharedpluralrules.h"
#include "unifiedcache.h"
-#include "number_decimalquantity.h"
-#include "util.h"
+#include "number_decimalquantity.h"
+#include "util.h"
#if !UCONFIG_NO_FORMATTING
U_NAMESPACE_BEGIN
-using namespace icu::pluralimpl;
-using icu::number::impl::DecimalQuantity;
-
+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};
@@ -66,15 +66,15 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PluralKeywordEnumeration)
PluralRules::PluralRules(UErrorCode& /*status*/)
: UObject(),
- mRules(nullptr),
- mInternalStatus(U_ZERO_ERROR)
+ mRules(nullptr),
+ mInternalStatus(U_ZERO_ERROR)
{
}
PluralRules::PluralRules(const PluralRules& other)
: UObject(other),
- mRules(nullptr),
- mInternalStatus(U_ZERO_ERROR)
+ mRules(nullptr),
+ mInternalStatus(U_ZERO_ERROR)
{
*this=other;
}
@@ -89,67 +89,67 @@ SharedPluralRules::~SharedPluralRules() {
PluralRules*
PluralRules::clone() const {
- PluralRules* newObj = new PluralRules(*this);
- // Since clone doesn't have a 'status' parameter, the best we can do is return nullptr if
- // the newly created object was not fully constructed properly (an error occurred).
- if (newObj != nullptr && U_FAILURE(newObj->mInternalStatus)) {
- delete newObj;
- newObj = nullptr;
- }
- return newObj;
+ PluralRules* newObj = new PluralRules(*this);
+ // Since clone doesn't have a 'status' parameter, the best we can do is return nullptr if
+ // the newly created object was not fully constructed properly (an error occurred).
+ if (newObj != nullptr && U_FAILURE(newObj->mInternalStatus)) {
+ delete newObj;
+ newObj = nullptr;
+ }
+ return newObj;
}
PluralRules&
PluralRules::operator=(const PluralRules& other) {
if (this != &other) {
delete mRules;
- mRules = nullptr;
- mInternalStatus = other.mInternalStatus;
- if (U_FAILURE(mInternalStatus)) {
- // bail out early if the object we were copying from was already 'invalid'.
- return *this;
+ mRules = nullptr;
+ mInternalStatus = other.mInternalStatus;
+ if (U_FAILURE(mInternalStatus)) {
+ // bail out early if the object we were copying from was already 'invalid'.
+ return *this;
}
- if (other.mRules != nullptr) {
+ if (other.mRules != nullptr) {
mRules = new RuleChain(*other.mRules);
- if (mRules == nullptr) {
- mInternalStatus = U_MEMORY_ALLOCATION_ERROR;
- }
- else if (U_FAILURE(mRules->fInternalStatus)) {
- // If the RuleChain wasn't fully copied, then set our status to failure as well.
- mInternalStatus = mRules->fInternalStatus;
- }
+ if (mRules == nullptr) {
+ mInternalStatus = U_MEMORY_ALLOCATION_ERROR;
+ }
+ else if (U_FAILURE(mRules->fInternalStatus)) {
+ // If the RuleChain wasn't fully copied, then set our status to failure as well.
+ mInternalStatus = mRules->fInternalStatus;
+ }
}
}
return *this;
}
StringEnumeration* PluralRules::getAvailableLocales(UErrorCode &status) {
- if (U_FAILURE(status)) {
- return nullptr;
+ if (U_FAILURE(status)) {
+ return nullptr;
}
- LocalPointer<StringEnumeration> result(new PluralAvailableLocalesEnumeration(status), status);
+ LocalPointer<StringEnumeration> result(new PluralAvailableLocalesEnumeration(status), status);
if (U_FAILURE(status)) {
- return nullptr;
+ return nullptr;
}
- return result.orphan();
+ return result.orphan();
}
PluralRules* U_EXPORT2
PluralRules::createRules(const UnicodeString& description, UErrorCode& status) {
if (U_FAILURE(status)) {
- return nullptr;
+ return nullptr;
}
PluralRuleParser parser;
- LocalPointer<PluralRules> newRules(new PluralRules(status), status);
- if (U_FAILURE(status)) {
- return nullptr;
+ LocalPointer<PluralRules> newRules(new PluralRules(status), status);
+ if (U_FAILURE(status)) {
+ return nullptr;
}
- parser.parse(description, newRules.getAlias(), status);
+ parser.parse(description, newRules.getAlias(), status);
if (U_FAILURE(status)) {
- newRules.adoptInstead(nullptr);
+ newRules.adoptInstead(nullptr);
}
- return newRules.orphan();
+ return newRules.orphan();
}
@@ -165,17 +165,17 @@ template<> U_I18N_API
const SharedPluralRules *LocaleCacheKey<SharedPluralRules>::createObject(
const void * /*unused*/, UErrorCode &status) const {
const char *localeId = fLoc.getName();
- LocalPointer<PluralRules> pr(PluralRules::internalForLocale(localeId, UPLURAL_TYPE_CARDINAL, status), status);
+ LocalPointer<PluralRules> pr(PluralRules::internalForLocale(localeId, UPLURAL_TYPE_CARDINAL, status), status);
if (U_FAILURE(status)) {
- return nullptr;
+ return nullptr;
}
- LocalPointer<SharedPluralRules> result(new SharedPluralRules(pr.getAlias()), status);
- if (U_FAILURE(status)) {
- return nullptr;
+ LocalPointer<SharedPluralRules> result(new SharedPluralRules(pr.getAlias()), status);
+ if (U_FAILURE(status)) {
+ return nullptr;
}
- pr.orphan(); // result was successfully created so it nows pr.
+ pr.orphan(); // result was successfully created so it nows pr.
result->addRef();
- return result.orphan();
+ return result.orphan();
}
/* end plural rules cache */
@@ -185,13 +185,13 @@ const SharedPluralRules* U_EXPORT2
PluralRules::createSharedInstance(
const Locale& locale, UPluralType type, UErrorCode& status) {
if (U_FAILURE(status)) {
- return nullptr;
+ return nullptr;
}
if (type != UPLURAL_TYPE_CARDINAL) {
status = U_UNSUPPORTED_ERROR;
- return nullptr;
+ return nullptr;
}
- const SharedPluralRules *result = nullptr;
+ const SharedPluralRules *result = nullptr;
UnifiedCache::getByLocale(locale, result, status);
return result;
}
@@ -209,11 +209,11 @@ PluralRules::forLocale(const Locale& locale, UPluralType type, UErrorCode& statu
const SharedPluralRules *shared = createSharedInstance(
locale, type, status);
if (U_FAILURE(status)) {
- return nullptr;
+ return nullptr;
}
PluralRules *result = (*shared)->clone();
shared->removeRef();
- if (result == nullptr) {
+ if (result == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
}
return result;
@@ -222,23 +222,23 @@ PluralRules::forLocale(const Locale& locale, UPluralType type, UErrorCode& statu
PluralRules* U_EXPORT2
PluralRules::internalForLocale(const Locale& locale, UPluralType type, UErrorCode& status) {
if (U_FAILURE(status)) {
- return nullptr;
+ return nullptr;
}
if (type >= UPLURAL_TYPE_COUNT) {
status = U_ILLEGAL_ARGUMENT_ERROR;
- return nullptr;
+ return nullptr;
}
- LocalPointer<PluralRules> newObj(new PluralRules(status), status);
- if (U_FAILURE(status)) {
- return nullptr;
+ LocalPointer<PluralRules> newObj(new PluralRules(status), status);
+ if (U_FAILURE(status)) {
+ return nullptr;
}
UnicodeString locRule = newObj->getRuleFromResource(locale, type, status);
- // TODO: which other errors, if any, should be returned?
+ // TODO: which other errors, if any, should be returned?
if (locRule.length() == 0) {
- // If an out-of-memory error occurred, then stop and report the failure.
- if (status == U_MEMORY_ALLOCATION_ERROR) {
- return nullptr;
- }
+ // If an out-of-memory error occurred, then stop and report the failure.
+ if (status == U_MEMORY_ALLOCATION_ERROR) {
+ return nullptr;
+ }
// Locales with no specific rules (all numbers have the "other" category
// will return a U_MISSING_RESOURCE_ERROR at this point. This is not
// an error.
@@ -246,13 +246,13 @@ PluralRules::internalForLocale(const Locale& locale, UPluralType type, UErrorCod
status = U_ZERO_ERROR;
}
PluralRuleParser parser;
- parser.parse(locRule, newObj.getAlias(), status);
+ parser.parse(locRule, newObj.getAlias(), status);
// TODO: should rule parse errors be returned, or
// should we silently use default rules?
// Original impl used default rules.
// Ask the question to ICU Core.
- return newObj.orphan();
+ return newObj.orphan();
}
UnicodeString
@@ -266,23 +266,23 @@ PluralRules::select(double number) const {
}
UnicodeString
-PluralRules::select(const number::FormattedNumber& number, UErrorCode& status) const {
- DecimalQuantity dq;
- number.getDecimalQuantity(dq, status);
- if (U_FAILURE(status)) {
- return ICU_Utility::makeBogusString();
+PluralRules::select(const number::FormattedNumber& number, UErrorCode& status) const {
+ DecimalQuantity dq;
+ number.getDecimalQuantity(dq, status);
+ if (U_FAILURE(status)) {
+ return ICU_Utility::makeBogusString();
}
- return select(dq);
+ return select(dq);
}
UnicodeString
-PluralRules::select(const IFixedDecimal &number) const {
- if (mRules == nullptr) {
+PluralRules::select(const IFixedDecimal &number) const {
+ if (mRules == nullptr) {
return UnicodeString(TRUE, PLURAL_DEFAULT_RULE, -1);
}
- else {
- return mRules->select(number);
- }
+ else {
+ return mRules->select(number);
+ }
}
@@ -290,17 +290,17 @@ PluralRules::select(const IFixedDecimal &number) const {
StringEnumeration*
PluralRules::getKeywords(UErrorCode& status) const {
if (U_FAILURE(status)) {
- return nullptr;
- }
- if (U_FAILURE(mInternalStatus)) {
- status = mInternalStatus;
- return nullptr;
- }
- LocalPointer<StringEnumeration> nameEnumerator(new PluralKeywordEnumeration(mRules, status), status);
- if (U_FAILURE(status)) {
- return nullptr;
+ return nullptr;
}
- return nameEnumerator.orphan();
+ if (U_FAILURE(mInternalStatus)) {
+ status = mInternalStatus;
+ return nullptr;
+ }
+ LocalPointer<StringEnumeration> nameEnumerator(new PluralKeywordEnumeration(mRules, status), status);
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ return nameEnumerator.orphan();
}
double
@@ -316,7 +316,7 @@ PluralRules::getAllKeywordValues(const UnicodeString & /* keyword */, double * /
return 0;
}
-
+
static double scaleForInt(double d) {
double scale = 1.0;
while (d != floor(d)) {
@@ -351,7 +351,7 @@ getSamplesFromString(const UnicodeString &samples, double *dest,
dest[sampleCount++] = sampleValue;
}
} else {
-
+
FixedDecimal fixedLo(sampleRange.tempSubStringBetween(0, tildeIndex), status);
FixedDecimal fixedHi(sampleRange.tempSubStringBetween(tildeIndex+1), status);
double rangeLo = fixedLo.source;
@@ -367,7 +367,7 @@ getSamplesFromString(const UnicodeString &samples, double *dest,
// For ranges of samples with fraction decimal digits, scale the number up so that we
// are adding one in the units place. Avoids roundoffs from repetitive adds of tenths.
- double scale = scaleForInt(rangeLo);
+ double scale = scaleForInt(rangeLo);
double t = scaleForInt(rangeHi);
if (t > scale) {
scale = t;
@@ -398,28 +398,28 @@ getSamplesFromString(const UnicodeString &samples, double *dest,
int32_t
PluralRules::getSamples(const UnicodeString &keyword, double *dest,
int32_t destCapacity, UErrorCode& status) {
- if (destCapacity == 0 || U_FAILURE(status)) {
- return 0;
- }
- if (U_FAILURE(mInternalStatus)) {
- status = mInternalStatus;
- return 0;
- }
+ if (destCapacity == 0 || U_FAILURE(status)) {
+ return 0;
+ }
+ if (U_FAILURE(mInternalStatus)) {
+ status = mInternalStatus;
+ return 0;
+ }
RuleChain *rc = rulesForKeyword(keyword);
- if (rc == nullptr) {
+ if (rc == nullptr) {
return 0;
}
int32_t numSamples = getSamplesFromString(rc->fIntegerSamples, dest, destCapacity, status);
- if (numSamples == 0) {
+ if (numSamples == 0) {
numSamples = getSamplesFromString(rc->fDecimalSamples, dest, destCapacity, status);
}
return numSamples;
}
-
+
RuleChain *PluralRules::rulesForKeyword(const UnicodeString &keyword) const {
RuleChain *rc;
- for (rc = mRules; rc != nullptr; rc = rc->fNext) {
+ for (rc = mRules; rc != nullptr; rc = rc->fNext) {
if (rc->fKeyword == keyword) {
break;
}
@@ -433,7 +433,7 @@ PluralRules::isKeyword(const UnicodeString& keyword) const {
if (0 == keyword.compare(PLURAL_KEYWORD_OTHER, 5)) {
return true;
}
- return rulesForKeyword(keyword) != nullptr;
+ return rulesForKeyword(keyword) != nullptr;
}
UnicodeString
@@ -459,13 +459,13 @@ PluralRules::operator==(const PluralRules& other) const {
return FALSE;
}
myKeywordList->reset(status);
- while ((ptrKeyword=myKeywordList->snext(status))!=nullptr) {
+ while ((ptrKeyword=myKeywordList->snext(status))!=nullptr) {
if (!other.isKeyword(*ptrKeyword)) {
return FALSE;
}
}
otherKeywordList->reset(status);
- while ((ptrKeyword=otherKeywordList->snext(status))!=nullptr) {
+ while ((ptrKeyword=otherKeywordList->snext(status))!=nullptr) {
if (!this->isKeyword(*ptrKeyword)) {
return FALSE;
}
@@ -498,33 +498,33 @@ PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErr
}
switch (type) {
case tAnd:
- U_ASSERT(curAndConstraint != nullptr);
- curAndConstraint = curAndConstraint->add(status);
+ U_ASSERT(curAndConstraint != nullptr);
+ curAndConstraint = curAndConstraint->add(status);
break;
case tOr:
{
- U_ASSERT(currentChain != nullptr);
+ U_ASSERT(currentChain != nullptr);
OrConstraint *orNode=currentChain->ruleHeader;
- while (orNode->next != nullptr) {
+ while (orNode->next != nullptr) {
orNode = orNode->next;
}
orNode->next= new OrConstraint();
- if (orNode->next == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- break;
- }
+ if (orNode->next == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
orNode=orNode->next;
- orNode->next=nullptr;
- curAndConstraint = orNode->add(status);
+ orNode->next=nullptr;
+ curAndConstraint = orNode->add(status);
}
break;
case tIs:
- U_ASSERT(curAndConstraint != nullptr);
+ U_ASSERT(curAndConstraint != nullptr);
U_ASSERT(curAndConstraint->value == -1);
- U_ASSERT(curAndConstraint->rangeList == nullptr);
+ U_ASSERT(curAndConstraint->rangeList == nullptr);
break;
case tNot:
- U_ASSERT(curAndConstraint != nullptr);
+ U_ASSERT(curAndConstraint != nullptr);
curAndConstraint->negated=TRUE;
break;
@@ -534,29 +534,29 @@ PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErr
case tIn:
case tWithin:
case tEqual:
- {
- U_ASSERT(curAndConstraint != nullptr);
- LocalPointer<UVector32> newRangeList(new UVector32(status), status);
- if (U_FAILURE(status)) {
- break;
- }
- curAndConstraint->rangeList = newRangeList.orphan();
- curAndConstraint->rangeList->addElement(-1, status); // range Low
- curAndConstraint->rangeList->addElement(-1, status); // range Hi
- rangeLowIdx = 0;
- rangeHiIdx = 1;
- curAndConstraint->value=PLURAL_RANGE_HIGH;
- curAndConstraint->integerOnly = (type != tWithin);
- }
+ {
+ U_ASSERT(curAndConstraint != nullptr);
+ LocalPointer<UVector32> newRangeList(new UVector32(status), status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ curAndConstraint->rangeList = newRangeList.orphan();
+ curAndConstraint->rangeList->addElement(-1, status); // range Low
+ curAndConstraint->rangeList->addElement(-1, status); // range Hi
+ rangeLowIdx = 0;
+ rangeHiIdx = 1;
+ curAndConstraint->value=PLURAL_RANGE_HIGH;
+ curAndConstraint->integerOnly = (type != tWithin);
+ }
break;
case tNumber:
- U_ASSERT(curAndConstraint != nullptr);
+ U_ASSERT(curAndConstraint != nullptr);
if ( (curAndConstraint->op==AndConstraint::MOD)&&
(curAndConstraint->opNum == -1 ) ) {
curAndConstraint->opNum=getNumberValue(token);
}
else {
- if (curAndConstraint->rangeList == nullptr) {
+ if (curAndConstraint->rangeList == nullptr) {
// this is for an 'is' rule
curAndConstraint->value = getNumberValue(token);
} else {
@@ -567,7 +567,7 @@ PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErr
}
else {
curAndConstraint->rangeList->setElementAt(getNumberValue(token), rangeHiIdx);
- if (curAndConstraint->rangeList->elementAti(rangeLowIdx) >
+ if (curAndConstraint->rangeList->elementAti(rangeLowIdx) >
curAndConstraint->rangeList->elementAti(rangeHiIdx)) {
// Range Lower bound > Range Upper bound.
// U_UNEXPECTED_TOKEN seems a little funny, but it is consistently
@@ -582,7 +582,7 @@ PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErr
case tComma:
// TODO: rule syntax checking is inadequate, can happen with badly formed rules.
// Catch cases like "n mod 10, is 1" here instead.
- if (curAndConstraint == nullptr || curAndConstraint->rangeList == nullptr) {
+ if (curAndConstraint == nullptr || curAndConstraint->rangeList == nullptr) {
status = U_UNEXPECTED_TOKEN;
break;
}
@@ -593,7 +593,7 @@ PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErr
curAndConstraint->rangeList->addElement(-1, status); // range Hi
break;
case tMod:
- U_ASSERT(curAndConstraint != nullptr);
+ U_ASSERT(curAndConstraint != nullptr);
curAndConstraint->op=AndConstraint::MOD;
break;
case tVariableN:
@@ -601,24 +601,24 @@ PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErr
case tVariableF:
case tVariableT:
case tVariableV:
- U_ASSERT(curAndConstraint != nullptr);
+ U_ASSERT(curAndConstraint != nullptr);
curAndConstraint->digitsType = type;
break;
case tKeyword:
{
RuleChain *newChain = new RuleChain;
- if (newChain == nullptr) {
+ if (newChain == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
break;
}
newChain->fKeyword = token;
- if (prules->mRules == nullptr) {
+ if (prules->mRules == nullptr) {
prules->mRules = newChain;
} else {
// The new rule chain goes at the end of the linked list of rule chains,
// unless there is an "other" keyword & chain. "other" must remain last.
RuleChain *insertAfter = prules->mRules;
- while (insertAfter->fNext!=nullptr &&
+ while (insertAfter->fNext!=nullptr &&
insertAfter->fNext->fKeyword.compare(PLURAL_KEYWORD_OTHER, 5) != 0 ){
insertAfter=insertAfter->fNext;
}
@@ -626,12 +626,12 @@ PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErr
insertAfter->fNext = newChain;
}
OrConstraint *orNode = new OrConstraint();
- if (orNode == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- break;
- }
+ if (orNode == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
newChain->ruleHeader = orNode;
- curAndConstraint = orNode->add(status);
+ curAndConstraint = orNode->add(status);
currentChain = newChain;
}
break;
@@ -663,7 +663,7 @@ PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErr
currentChain->fDecimalSamples.append(token);
}
break;
-
+
default:
break;
}
@@ -681,7 +681,7 @@ PluralRules::getRuleFromResource(const Locale& locale, UPluralType type, UErrorC
if (U_FAILURE(errCode)) {
return emptyStr;
}
- LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "plurals", &errCode));
+ LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "plurals", &errCode));
if(U_FAILURE(errCode)) {
return emptyStr;
}
@@ -698,33 +698,33 @@ PluralRules::getRuleFromResource(const Locale& locale, UPluralType type, UErrorC
errCode = U_ILLEGAL_ARGUMENT_ERROR;
return emptyStr;
}
- LocalUResourceBundlePointer locRes(ures_getByKey(rb.getAlias(), typeKey, nullptr, &errCode));
+ LocalUResourceBundlePointer locRes(ures_getByKey(rb.getAlias(), typeKey, nullptr, &errCode));
if(U_FAILURE(errCode)) {
return emptyStr;
}
int32_t resLen=0;
- const char *curLocaleName=locale.getBaseName();
+ const char *curLocaleName=locale.getBaseName();
const UChar* s = ures_getStringByKey(locRes.getAlias(), curLocaleName, &resLen, &errCode);
- if (s == nullptr) {
+ if (s == nullptr) {
// Check parent locales.
UErrorCode status = U_ZERO_ERROR;
char parentLocaleName[ULOC_FULLNAME_CAPACITY];
- const char *curLocaleName2=locale.getBaseName();
- uprv_strcpy(parentLocaleName, curLocaleName2);
+ const char *curLocaleName2=locale.getBaseName();
+ uprv_strcpy(parentLocaleName, curLocaleName2);
while (uloc_getParent(parentLocaleName, parentLocaleName,
ULOC_FULLNAME_CAPACITY, &status) > 0) {
resLen=0;
s = ures_getStringByKey(locRes.getAlias(), parentLocaleName, &resLen, &status);
- if (s != nullptr) {
+ if (s != nullptr) {
errCode = U_ZERO_ERROR;
break;
}
status = U_ZERO_ERROR;
}
}
- if (s==nullptr) {
+ if (s==nullptr) {
return emptyStr;
}
@@ -732,18 +732,18 @@ PluralRules::getRuleFromResource(const Locale& locale, UPluralType type, UErrorC
u_UCharsToChars(s, setKey, resLen + 1);
// printf("\n PluralRule: %s\n", setKey);
- LocalUResourceBundlePointer ruleRes(ures_getByKey(rb.getAlias(), "rules", nullptr, &errCode));
+ LocalUResourceBundlePointer ruleRes(ures_getByKey(rb.getAlias(), "rules", nullptr, &errCode));
if(U_FAILURE(errCode)) {
return emptyStr;
}
- LocalUResourceBundlePointer setRes(ures_getByKey(ruleRes.getAlias(), setKey, nullptr, &errCode));
+ LocalUResourceBundlePointer setRes(ures_getByKey(ruleRes.getAlias(), setKey, nullptr, &errCode));
if (U_FAILURE(errCode)) {
return emptyStr;
}
int32_t numberKeys = ures_getSize(setRes.getAlias());
UnicodeString result;
- const char *key=nullptr;
+ const char *key=nullptr;
for(int32_t i=0; i<numberKeys; ++i) { // Keys are zero, one, few, ...
UnicodeString rules = ures_getNextUnicodeString(setRes.getAlias(), &key, &errCode);
UnicodeString uKey(key, -1, US_INV);
@@ -759,58 +759,58 @@ PluralRules::getRuleFromResource(const Locale& locale, UPluralType type, UErrorC
UnicodeString
PluralRules::getRules() const {
UnicodeString rules;
- if (mRules != nullptr) {
+ if (mRules != nullptr) {
mRules->dumpRules(rules);
}
return rules;
}
AndConstraint::AndConstraint(const AndConstraint& other) {
- this->fInternalStatus = other.fInternalStatus;
- if (U_FAILURE(fInternalStatus)) {
- return; // stop early if the object we are copying from is invalid.
- }
+ this->fInternalStatus = other.fInternalStatus;
+ if (U_FAILURE(fInternalStatus)) {
+ return; // stop early if the object we are copying from is invalid.
+ }
this->op = other.op;
this->opNum=other.opNum;
this->value=other.value;
- if (other.rangeList != nullptr) {
- LocalPointer<UVector32> newRangeList(new UVector32(fInternalStatus), fInternalStatus);
- if (U_FAILURE(fInternalStatus)) {
- return;
- }
- this->rangeList = newRangeList.orphan();
- this->rangeList->assign(*other.rangeList, fInternalStatus);
+ if (other.rangeList != nullptr) {
+ LocalPointer<UVector32> newRangeList(new UVector32(fInternalStatus), fInternalStatus);
+ if (U_FAILURE(fInternalStatus)) {
+ return;
+ }
+ this->rangeList = newRangeList.orphan();
+ this->rangeList->assign(*other.rangeList, fInternalStatus);
}
this->integerOnly=other.integerOnly;
this->negated=other.negated;
this->digitsType = other.digitsType;
- if (other.next != nullptr) {
+ if (other.next != nullptr) {
this->next = new AndConstraint(*other.next);
- if (this->next == nullptr) {
- fInternalStatus = U_MEMORY_ALLOCATION_ERROR;
- }
+ if (this->next == nullptr) {
+ fInternalStatus = U_MEMORY_ALLOCATION_ERROR;
+ }
}
}
AndConstraint::~AndConstraint() {
delete rangeList;
- rangeList = nullptr;
- delete next;
- next = nullptr;
+ rangeList = nullptr;
+ delete next;
+ next = nullptr;
}
UBool
-AndConstraint::isFulfilled(const IFixedDecimal &number) {
+AndConstraint::isFulfilled(const IFixedDecimal &number) {
UBool result = TRUE;
if (digitsType == none) {
// An empty AndConstraint, created by a rule with a keyword but no following expression.
return TRUE;
}
-
- PluralOperand operand = tokenTypeToPluralOperand(digitsType);
- double n = number.getPluralOperand(operand); // pulls n | i | v | f value for the number.
- // Will always be positive.
- // May be non-integer (n option only)
+
+ PluralOperand operand = tokenTypeToPluralOperand(digitsType);
+ double n = number.getPluralOperand(operand); // pulls n | i | v | f value for the number.
+ // Will always be positive.
+ // May be non-integer (n option only)
do {
if (integerOnly && n != uprv_floor(n)) {
result = FALSE;
@@ -820,7 +820,7 @@ AndConstraint::isFulfilled(const IFixedDecimal &number) {
if (op == MOD) {
n = fmod(n, opNum);
}
- if (rangeList == nullptr) {
+ if (rangeList == nullptr) {
result = value == -1 || // empty rule
n == value; // 'is' rule
break;
@@ -841,79 +841,79 @@ AndConstraint::isFulfilled(const IFixedDecimal &number) {
}
AndConstraint*
-AndConstraint::add(UErrorCode& status) {
- if (U_FAILURE(fInternalStatus)) {
- status = fInternalStatus;
- return nullptr;
- }
+AndConstraint::add(UErrorCode& status) {
+ if (U_FAILURE(fInternalStatus)) {
+ status = fInternalStatus;
+ return nullptr;
+ }
this->next = new AndConstraint();
- if (this->next == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
+ if (this->next == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
return this->next;
}
OrConstraint::OrConstraint(const OrConstraint& other) {
- this->fInternalStatus = other.fInternalStatus;
- if (U_FAILURE(fInternalStatus)) {
- return; // stop early if the object we are copying from is invalid.
+ this->fInternalStatus = other.fInternalStatus;
+ if (U_FAILURE(fInternalStatus)) {
+ return; // stop early if the object we are copying from is invalid.
}
- if ( other.childNode != nullptr ) {
+ if ( other.childNode != nullptr ) {
this->childNode = new AndConstraint(*(other.childNode));
- if (this->childNode == nullptr) {
- fInternalStatus = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
+ if (this->childNode == nullptr) {
+ fInternalStatus = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
}
- if (other.next != nullptr ) {
+ if (other.next != nullptr ) {
this->next = new OrConstraint(*(other.next));
- if (this->next == nullptr) {
- fInternalStatus = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- if (U_FAILURE(this->next->fInternalStatus)) {
- this->fInternalStatus = this->next->fInternalStatus;
- }
+ if (this->next == nullptr) {
+ fInternalStatus = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ if (U_FAILURE(this->next->fInternalStatus)) {
+ this->fInternalStatus = this->next->fInternalStatus;
+ }
}
}
OrConstraint::~OrConstraint() {
- delete childNode;
- childNode = nullptr;
- delete next;
- next = nullptr;
+ delete childNode;
+ childNode = nullptr;
+ delete next;
+ next = nullptr;
}
AndConstraint*
-OrConstraint::add(UErrorCode& status) {
- if (U_FAILURE(fInternalStatus)) {
- status = fInternalStatus;
- return nullptr;
- }
+OrConstraint::add(UErrorCode& status) {
+ if (U_FAILURE(fInternalStatus)) {
+ status = fInternalStatus;
+ return nullptr;
+ }
OrConstraint *curOrConstraint=this;
{
- while (curOrConstraint->next!=nullptr) {
+ while (curOrConstraint->next!=nullptr) {
curOrConstraint = curOrConstraint->next;
}
- U_ASSERT(curOrConstraint->childNode == nullptr);
+ U_ASSERT(curOrConstraint->childNode == nullptr);
curOrConstraint->childNode = new AndConstraint();
- if (curOrConstraint->childNode == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
+ if (curOrConstraint->childNode == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
}
return curOrConstraint->childNode;
}
UBool
-OrConstraint::isFulfilled(const IFixedDecimal &number) {
+OrConstraint::isFulfilled(const IFixedDecimal &number) {
OrConstraint* orRule=this;
UBool result=FALSE;
- while (orRule!=nullptr && !result) {
+ while (orRule!=nullptr && !result) {
result=TRUE;
AndConstraint* andRule = orRule->childNode;
- while (andRule!=nullptr && result) {
+ while (andRule!=nullptr && result) {
result = andRule->isFulfilled(number);
andRule=andRule->next;
}
@@ -924,33 +924,33 @@ OrConstraint::isFulfilled(const IFixedDecimal &number) {
}
-RuleChain::RuleChain(const RuleChain& other) :
- fKeyword(other.fKeyword), fDecimalSamples(other.fDecimalSamples),
- fIntegerSamples(other.fIntegerSamples), fDecimalSamplesUnbounded(other.fDecimalSamplesUnbounded),
- fIntegerSamplesUnbounded(other.fIntegerSamplesUnbounded), fInternalStatus(other.fInternalStatus) {
- if (U_FAILURE(this->fInternalStatus)) {
- return; // stop early if the object we are copying from is invalid.
- }
- if (other.ruleHeader != nullptr) {
+RuleChain::RuleChain(const RuleChain& other) :
+ fKeyword(other.fKeyword), fDecimalSamples(other.fDecimalSamples),
+ fIntegerSamples(other.fIntegerSamples), fDecimalSamplesUnbounded(other.fDecimalSamplesUnbounded),
+ fIntegerSamplesUnbounded(other.fIntegerSamplesUnbounded), fInternalStatus(other.fInternalStatus) {
+ if (U_FAILURE(this->fInternalStatus)) {
+ return; // stop early if the object we are copying from is invalid.
+ }
+ if (other.ruleHeader != nullptr) {
this->ruleHeader = new OrConstraint(*(other.ruleHeader));
- if (this->ruleHeader == nullptr) {
- this->fInternalStatus = U_MEMORY_ALLOCATION_ERROR;
- }
- else if (U_FAILURE(this->ruleHeader->fInternalStatus)) {
- // If the OrConstraint wasn't fully copied, then set our status to failure as well.
- this->fInternalStatus = this->ruleHeader->fInternalStatus;
- return; // exit early.
- }
- }
- if (other.fNext != nullptr ) {
+ if (this->ruleHeader == nullptr) {
+ this->fInternalStatus = U_MEMORY_ALLOCATION_ERROR;
+ }
+ else if (U_FAILURE(this->ruleHeader->fInternalStatus)) {
+ // If the OrConstraint wasn't fully copied, then set our status to failure as well.
+ this->fInternalStatus = this->ruleHeader->fInternalStatus;
+ return; // exit early.
+ }
+ }
+ if (other.fNext != nullptr ) {
this->fNext = new RuleChain(*other.fNext);
- if (this->fNext == nullptr) {
- this->fInternalStatus = U_MEMORY_ALLOCATION_ERROR;
- }
- else if (U_FAILURE(this->fNext->fInternalStatus)) {
- // If the RuleChain wasn't fully copied, then set our status to failure as well.
- this->fInternalStatus = this->fNext->fInternalStatus;
- }
+ if (this->fNext == nullptr) {
+ this->fInternalStatus = U_MEMORY_ALLOCATION_ERROR;
+ }
+ else if (U_FAILURE(this->fNext->fInternalStatus)) {
+ // If the RuleChain wasn't fully copied, then set our status to failure as well.
+ this->fInternalStatus = this->fNext->fInternalStatus;
+ }
}
}
@@ -960,9 +960,9 @@ RuleChain::~RuleChain() {
}
UnicodeString
-RuleChain::select(const IFixedDecimal &number) const {
- if (!number.isNaN() && !number.isInfinite()) {
- for (const RuleChain *rules = this; rules != nullptr; rules = rules->fNext) {
+RuleChain::select(const IFixedDecimal &number) const {
+ if (!number.isNaN() && !number.isInfinite()) {
+ for (const RuleChain *rules = this; rules != nullptr; rules = rules->fNext) {
if (rules->ruleHeader->isFulfilled(number)) {
return rules->fKeyword;
}
@@ -994,17 +994,17 @@ void
RuleChain::dumpRules(UnicodeString& result) {
UChar digitString[16];
- if ( ruleHeader != nullptr ) {
+ if ( ruleHeader != nullptr ) {
result += fKeyword;
result += COLON;
result += SPACE;
OrConstraint* orRule=ruleHeader;
- while ( orRule != nullptr ) {
+ while ( orRule != nullptr ) {
AndConstraint* andRule=orRule->childNode;
- while ( andRule != nullptr ) {
- if ((andRule->op==AndConstraint::NONE) && (andRule->rangeList==nullptr) && (andRule->value == -1)) {
+ while ( andRule != nullptr ) {
+ if ((andRule->op==AndConstraint::NONE) && (andRule->rangeList==nullptr) && (andRule->value == -1)) {
// Empty Rules.
- } else if ( (andRule->op==AndConstraint::NONE) && (andRule->rangeList==nullptr) ) {
+ } else if ( (andRule->op==AndConstraint::NONE) && (andRule->rangeList==nullptr) ) {
result += tokenString(andRule->digitsType);
result += UNICODE_STRING_SIMPLE(" is ");
if (andRule->negated) {
@@ -1021,7 +1021,7 @@ RuleChain::dumpRules(UnicodeString& result) {
uprv_itou(digitString,16, andRule->opNum,10,0);
result += UnicodeString(digitString);
}
- if (andRule->rangeList==nullptr) {
+ if (andRule->rangeList==nullptr) {
if (andRule->negated) {
result += UNICODE_STRING_SIMPLE(" is not ");
uprv_itou(digitString,16, andRule->value,10,0);
@@ -1064,16 +1064,16 @@ RuleChain::dumpRules(UnicodeString& result) {
}
}
}
- if ( (andRule=andRule->next) != nullptr) {
+ if ( (andRule=andRule->next) != nullptr) {
result += UNICODE_STRING_SIMPLE(" and ");
}
}
- if ( (orRule = orRule->next) != nullptr ) {
+ if ( (orRule = orRule->next) != nullptr ) {
result += UNICODE_STRING_SIMPLE(" or ");
}
}
}
- if ( fNext != nullptr ) {
+ if ( fNext != nullptr ) {
result += UNICODE_STRING_SIMPLE("; ");
fNext->dumpRules(result);
}
@@ -1082,9 +1082,9 @@ RuleChain::dumpRules(UnicodeString& result) {
UErrorCode
RuleChain::getKeywords(int32_t capacityOfKeywords, UnicodeString* keywords, int32_t& arraySize) const {
- if (U_FAILURE(fInternalStatus)) {
- return fInternalStatus;
- }
+ if (U_FAILURE(fInternalStatus)) {
+ return fInternalStatus;
+ }
if ( arraySize < capacityOfKeywords-1 ) {
keywords[arraySize++]=fKeyword;
}
@@ -1092,7 +1092,7 @@ RuleChain::getKeywords(int32_t capacityOfKeywords, UnicodeString* keywords, int3
return U_BUFFER_OVERFLOW_ERROR;
}
- if ( fNext != nullptr ) {
+ if ( fNext != nullptr ) {
return fNext->getKeywords(capacityOfKeywords, keywords, arraySize);
}
else {
@@ -1106,7 +1106,7 @@ RuleChain::isKeyword(const UnicodeString& keywordParam) const {
return TRUE;
}
- if ( fNext != nullptr ) {
+ if ( fNext != nullptr ) {
return fNext->isKeyword(keywordParam);
}
else {
@@ -1115,9 +1115,9 @@ RuleChain::isKeyword(const UnicodeString& keywordParam) const {
}
-PluralRuleParser::PluralRuleParser() :
- ruleIndex(0), token(), type(none), prevType(none),
- curAndConstraint(nullptr), currentChain(nullptr), rangeLowIdx(-1), rangeHiIdx(-1)
+PluralRuleParser::PluralRuleParser() :
+ ruleIndex(0), token(), type(none), prevType(none),
+ curAndConstraint(nullptr), currentChain(nullptr), rangeLowIdx(-1), rangeHiIdx(-1)
{
}
@@ -1218,8 +1218,8 @@ PluralRuleParser::checkSyntax(UErrorCode &status)
break;
case tNumber:
if (type != tDot2 && type != tSemiColon && type != tIs && type != tNot &&
- type != tIn && type != tEqual && type != tNotEqual && type != tWithin &&
- type != tAnd && type != tOr && type != tComma && type != tAt &&
+ type != tIn && type != tEqual && type != tNotEqual && type != tWithin &&
+ type != tAnd && type != tOr && type != tComma && type != tAt &&
type != tEOF)
{
status = U_UNEXPECTED_TOKEN;
@@ -1264,7 +1264,7 @@ PluralRuleParser::getNextToken(UErrorCode &status)
return;
}
int32_t curIndex= ruleIndex;
-
+
switch (type) {
case tColon:
case tSemiColon:
@@ -1369,7 +1369,7 @@ PluralRuleParser::charType(UChar ch) {
// Set token type for reserved words in the Plural Rule syntax.
-tokenType
+tokenType
PluralRuleParser::getKeyType(const UnicodeString &token, tokenType keyType)
{
if (keyType != tKeyword) {
@@ -1415,36 +1415,36 @@ PluralKeywordEnumeration::PluralKeywordEnumeration(RuleChain *header, UErrorCode
return;
}
fKeywordNames.setDeleter(uprv_deleteUObject);
- UBool addKeywordOther = TRUE;
- RuleChain *node = header;
- while (node != nullptr) {
- auto newElem = new UnicodeString(node->fKeyword);
- if (newElem == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- fKeywordNames.addElement(newElem, status);
+ UBool addKeywordOther = TRUE;
+ RuleChain *node = header;
+ while (node != nullptr) {
+ auto newElem = new UnicodeString(node->fKeyword);
+ if (newElem == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ fKeywordNames.addElement(newElem, status);
if (U_FAILURE(status)) {
- delete newElem;
+ delete newElem;
return;
}
if (0 == node->fKeyword.compare(PLURAL_KEYWORD_OTHER, 5)) {
- addKeywordOther = FALSE;
+ addKeywordOther = FALSE;
}
- node = node->fNext;
+ node = node->fNext;
}
if (addKeywordOther) {
- auto newElem = new UnicodeString(PLURAL_KEYWORD_OTHER);
- if (newElem == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- fKeywordNames.addElement(newElem, status);
- if (U_FAILURE(status)) {
- delete newElem;
- return;
- }
+ auto newElem = new UnicodeString(PLURAL_KEYWORD_OTHER);
+ if (newElem == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ fKeywordNames.addElement(newElem, status);
+ if (U_FAILURE(status)) {
+ delete newElem;
+ return;
+ }
}
}
@@ -1453,7 +1453,7 @@ PluralKeywordEnumeration::snext(UErrorCode& status) {
if (U_SUCCESS(status) && pos < fKeywordNames.size()) {
return (const UnicodeString*)fKeywordNames.elementAt(pos++);
}
- return nullptr;
+ return nullptr;
}
void
@@ -1463,27 +1463,27 @@ PluralKeywordEnumeration::reset(UErrorCode& /*status*/) {
int32_t
PluralKeywordEnumeration::count(UErrorCode& /*status*/) const {
- return fKeywordNames.size();
+ return fKeywordNames.size();
}
PluralKeywordEnumeration::~PluralKeywordEnumeration() {
}
-PluralOperand tokenTypeToPluralOperand(tokenType tt) {
- switch(tt) {
- case tVariableN:
- return PLURAL_OPERAND_N;
- case tVariableI:
- return PLURAL_OPERAND_I;
- case tVariableF:
- return PLURAL_OPERAND_F;
- case tVariableV:
- return PLURAL_OPERAND_V;
- case tVariableT:
- return PLURAL_OPERAND_T;
- default:
- UPRV_UNREACHABLE; // unexpected.
- }
+PluralOperand tokenTypeToPluralOperand(tokenType tt) {
+ switch(tt) {
+ case tVariableN:
+ return PLURAL_OPERAND_N;
+ case tVariableI:
+ return PLURAL_OPERAND_I;
+ case tVariableF:
+ return PLURAL_OPERAND_F;
+ case tVariableV:
+ return PLURAL_OPERAND_V;
+ case tVariableT:
+ return PLURAL_OPERAND_T;
+ default:
+ UPRV_UNREACHABLE; // unexpected.
+ }
}
FixedDecimal::FixedDecimal(double n, int32_t v, int64_t f) {
@@ -1523,14 +1523,14 @@ FixedDecimal::FixedDecimal() {
FixedDecimal::FixedDecimal(const UnicodeString &num, UErrorCode &status) {
CharString cs;
cs.appendInvariantChars(num, status);
- DecimalQuantity dl;
- dl.setToDecNumber(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.toDouble();
+ double n = dl.toDouble();
if (decimalPoint == -1) {
init(n, 0, 0);
} else {
@@ -1546,15 +1546,15 @@ 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;
+ _isNaN = other._isNaN;
+ _isInfinite = other._isInfinite;
}
-FixedDecimal::~FixedDecimal() = default;
-
+FixedDecimal::~FixedDecimal() = default;
+
void FixedDecimal::init(double n) {
int32_t numFractionDigits = decimals(n);
init(n, numFractionDigits, getFractionalDigits(n, numFractionDigits));
@@ -1564,16 +1564,16 @@ void FixedDecimal::init(double n) {
void FixedDecimal::init(double n, int32_t v, int64_t f) {
isNegative = n < 0.0;
source = fabs(n);
- _isNaN = uprv_isNaN(source);
- _isInfinite = uprv_isInfinite(source);
- if (_isNaN || _isInfinite) {
+ _isNaN = uprv_isNaN(source);
+ _isInfinite = uprv_isInfinite(source);
+ if (_isNaN || _isInfinite) {
v = 0;
f = 0;
intValue = 0;
- _hasIntegerValue = FALSE;
+ _hasIntegerValue = FALSE;
} else {
intValue = (int64_t)source;
- _hasIntegerValue = (source == intValue);
+ _hasIntegerValue = (source == intValue);
}
visibleDecimalDigitCount = v;
@@ -1635,7 +1635,7 @@ int32_t FixedDecimal::decimals(double n) {
if (buf[i] != '0') {
break;
}
- --numFractionDigits;
+ --numFractionDigits;
}
numFractionDigits -= exponent; // Fraction part of fixed point representation.
return numFractionDigits;
@@ -1685,36 +1685,36 @@ void FixedDecimal::adjustForMinFractionDigits(int32_t minFractionDigits) {
}
}
-
-double FixedDecimal::getPluralOperand(PluralOperand operand) const {
+
+double FixedDecimal::getPluralOperand(PluralOperand operand) const {
switch(operand) {
- case PLURAL_OPERAND_N: return source;
- case PLURAL_OPERAND_I: return static_cast<double>(intValue);
- case PLURAL_OPERAND_F: return static_cast<double>(decimalDigits);
- case PLURAL_OPERAND_T: return static_cast<double>(decimalDigitsWithoutTrailingZeros);
- case PLURAL_OPERAND_V: return visibleDecimalDigitCount;
- case PLURAL_OPERAND_E: return 0;
+ case PLURAL_OPERAND_N: return source;
+ case PLURAL_OPERAND_I: return static_cast<double>(intValue);
+ case PLURAL_OPERAND_F: return static_cast<double>(decimalDigits);
+ case PLURAL_OPERAND_T: return static_cast<double>(decimalDigitsWithoutTrailingZeros);
+ case PLURAL_OPERAND_V: return visibleDecimalDigitCount;
+ case PLURAL_OPERAND_E: return 0;
default:
- UPRV_UNREACHABLE; // unexpected.
- }
-}
-
-bool FixedDecimal::isNaN() const {
- return _isNaN;
-}
-
-bool FixedDecimal::isInfinite() const {
- return _isInfinite;
-}
-
-bool FixedDecimal::hasIntegerValue() const {
- return _hasIntegerValue;
-}
-
-bool FixedDecimal::isNanOrInfinity() const {
- return _isNaN || _isInfinite;
-}
-
+ UPRV_UNREACHABLE; // unexpected.
+ }
+}
+
+bool FixedDecimal::isNaN() const {
+ return _isNaN;
+}
+
+bool FixedDecimal::isInfinite() const {
+ return _isInfinite;
+}
+
+bool FixedDecimal::hasIntegerValue() const {
+ return _hasIntegerValue;
+}
+
+bool FixedDecimal::isNanOrInfinity() const {
+ return _isNaN || _isInfinite;
+}
+
int32_t FixedDecimal::getVisibleFractionDigitCount() const {
return visibleDecimalDigitCount;
}
@@ -1726,36 +1726,36 @@ PluralAvailableLocalesEnumeration::PluralAvailableLocalesEnumeration(UErrorCode
if (U_FAILURE(status)) {
return;
}
- fOpenStatus = U_ZERO_ERROR; // clear any warnings.
- LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "plurals", &fOpenStatus));
- fLocales = ures_getByKey(rb.getAlias(), "locales", nullptr, &fOpenStatus);
+ fOpenStatus = U_ZERO_ERROR; // clear any warnings.
+ LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "plurals", &fOpenStatus));
+ fLocales = ures_getByKey(rb.getAlias(), "locales", nullptr, &fOpenStatus);
}
PluralAvailableLocalesEnumeration::~PluralAvailableLocalesEnumeration() {
ures_close(fLocales);
ures_close(fRes);
- fLocales = nullptr;
- fRes = nullptr;
+ fLocales = nullptr;
+ fRes = nullptr;
}
const char *PluralAvailableLocalesEnumeration::next(int32_t *resultLength, UErrorCode &status) {
if (U_FAILURE(status)) {
- return nullptr;
+ return nullptr;
}
if (U_FAILURE(fOpenStatus)) {
status = fOpenStatus;
- return nullptr;
+ return nullptr;
}
fRes = ures_getNextResource(fLocales, fRes, &status);
- if (fRes == nullptr || U_FAILURE(status)) {
+ if (fRes == nullptr || U_FAILURE(status)) {
if (status == U_INDEX_OUTOFBOUNDS_ERROR) {
status = U_ZERO_ERROR;
}
- return nullptr;
+ return nullptr;
}
const char *result = ures_getKey(fRes);
- if (resultLength != nullptr) {
- *resultLength = static_cast<int32_t>(uprv_strlen(result));
+ if (resultLength != nullptr) {
+ *resultLength = static_cast<int32_t>(uprv_strlen(result));
}
return result;
}
diff --git a/contrib/libs/icu/i18n/plurrule_impl.h b/contrib/libs/icu/i18n/plurrule_impl.h
index 0dc44fb62e..90f1c0b21f 100644
--- a/contrib/libs/icu/i18n/plurrule_impl.h
+++ b/contrib/libs/icu/i18n/plurrule_impl.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -24,11 +24,11 @@
#include "unicode/format.h"
#include "unicode/locid.h"
#include "unicode/parseerr.h"
-#include "unicode/strenum.h"
+#include "unicode/strenum.h"
#include "unicode/ures.h"
#include "uvector.h"
#include "hash.h"
-#include "uassert.h"
+#include "uassert.h"
class PluralRulesTest;
@@ -40,75 +40,75 @@ class DigitInterval;
class PluralRules;
class VisibleDigits;
-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);
-
-}
-
-
+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;
enum tokenType {
@@ -181,93 +181,93 @@ private:
kRangeList,
kSamples
};
-};
-
-enum PluralOperand {
- /**
- * The double value of the entire number.
- */
- PLURAL_OPERAND_N,
-
- /**
- * The integer value, with the fraction digits truncated off.
- */
- PLURAL_OPERAND_I,
-
- /**
- * All visible fraction digits as an integer, including trailing zeros.
- */
- PLURAL_OPERAND_F,
-
- /**
- * Visible fraction digits as an integer, not including trailing zeros.
- */
- PLURAL_OPERAND_T,
-
- /**
- * Number of visible fraction digits.
- */
- PLURAL_OPERAND_V,
-
- /**
- * Number of visible fraction digits, not including trailing zeros.
- */
- PLURAL_OPERAND_W,
-
- /**
- * Suppressed exponent for compact notation (exponent needed in
- * scientific notation with compact notation to approximate i).
- */
- PLURAL_OPERAND_E,
-
- /**
- * THIS OPERAND IS DEPRECATED AND HAS BEEN REMOVED FROM THE SPEC.
- *
- * <p>Returns the integer value, but will fail if the number has fraction digits.
- * That is, using "j" instead of "i" is like implicitly adding "v is 0".
- *
- * <p>For example, "j is 3" is equivalent to "i is 3 and v is 0": it matches
- * "3" but not "3.1" or "3.0".
- */
- PLURAL_OPERAND_J
-};
-
-/**
- * Converts from the tokenType enum to PluralOperand. Asserts that the given
- * tokenType can be mapped to a PluralOperand.
- */
-PluralOperand tokenTypeToPluralOperand(tokenType tt);
-
-/**
- * An interface to FixedDecimal, allowing for other implementations.
- * @internal
- */
-class U_I18N_API IFixedDecimal {
- public:
- virtual ~IFixedDecimal();
-
- /**
- * Returns the value corresponding to the specified operand (n, i, f, t, v, or w).
- * If the operand is 'n', returns a double; otherwise, returns an integer.
- */
- virtual double getPluralOperand(PluralOperand operand) const = 0;
-
- virtual bool isNaN() const = 0;
-
- virtual bool isInfinite() const = 0;
-
- /** Whether the number has no nonzero fraction digits. */
- virtual bool hasIntegerValue() const = 0;
+};
+
+enum PluralOperand {
+ /**
+ * The double value of the entire number.
+ */
+ PLURAL_OPERAND_N,
+
+ /**
+ * The integer value, with the fraction digits truncated off.
+ */
+ PLURAL_OPERAND_I,
+
+ /**
+ * All visible fraction digits as an integer, including trailing zeros.
+ */
+ PLURAL_OPERAND_F,
+
+ /**
+ * Visible fraction digits as an integer, not including trailing zeros.
+ */
+ PLURAL_OPERAND_T,
+
+ /**
+ * Number of visible fraction digits.
+ */
+ PLURAL_OPERAND_V,
+
+ /**
+ * Number of visible fraction digits, not including trailing zeros.
+ */
+ PLURAL_OPERAND_W,
+
+ /**
+ * Suppressed exponent for compact notation (exponent needed in
+ * scientific notation with compact notation to approximate i).
+ */
+ PLURAL_OPERAND_E,
+
+ /**
+ * THIS OPERAND IS DEPRECATED AND HAS BEEN REMOVED FROM THE SPEC.
+ *
+ * <p>Returns the integer value, but will fail if the number has fraction digits.
+ * That is, using "j" instead of "i" is like implicitly adding "v is 0".
+ *
+ * <p>For example, "j is 3" is equivalent to "i is 3 and v is 0": it matches
+ * "3" but not "3.1" or "3.0".
+ */
+ PLURAL_OPERAND_J
};
/**
+ * Converts from the tokenType enum to PluralOperand. Asserts that the given
+ * tokenType can be mapped to a PluralOperand.
+ */
+PluralOperand tokenTypeToPluralOperand(tokenType tt);
+
+/**
+ * An interface to FixedDecimal, allowing for other implementations.
+ * @internal
+ */
+class U_I18N_API IFixedDecimal {
+ public:
+ virtual ~IFixedDecimal();
+
+ /**
+ * Returns the value corresponding to the specified operand (n, i, f, t, v, or w).
+ * If the operand is 'n', returns a double; otherwise, returns an integer.
+ */
+ virtual double getPluralOperand(PluralOperand operand) const = 0;
+
+ virtual bool isNaN() const = 0;
+
+ virtual bool isInfinite() const = 0;
+
+ /** Whether the number has no nonzero fraction digits. */
+ virtual bool hasIntegerValue() const = 0;
+};
+
+/**
* class FixedDecimal serves to communicate the properties
* of a formatted number from a decimal formatter to PluralRules::select()
*
* see DecimalFormat::getFixedDecimal()
* @internal
*/
-class U_I18N_API FixedDecimal: public IFixedDecimal, public UObject {
+class U_I18N_API FixedDecimal: public IFixedDecimal, public UObject {
public:
/**
* @param n the number, e.g. 12.345
@@ -278,17 +278,17 @@ class U_I18N_API FixedDecimal: public IFixedDecimal, public UObject {
FixedDecimal(double n, int32_t);
explicit FixedDecimal(double n);
FixedDecimal();
- ~FixedDecimal() U_OVERRIDE;
+ ~FixedDecimal() U_OVERRIDE;
FixedDecimal(const UnicodeString &s, UErrorCode &ec);
FixedDecimal(const FixedDecimal &other);
- 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
-
+ 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
+
int32_t getVisibleFractionDigitCount() const;
void init(double n, int32_t v, int64_t f);
@@ -304,10 +304,10 @@ 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;
+ UBool _isNaN;
+ UBool _isInfinite;
};
class AndConstraint : public UMemory {
@@ -316,57 +316,57 @@ public:
NONE,
MOD
} RuleOp;
- RuleOp op = AndConstraint::NONE;
- int32_t opNum = -1; // for mod expressions, the right operand of the mod.
- int32_t value = -1; // valid for 'is' rules only.
- UVector32 *rangeList = nullptr; // for 'in', 'within' rules. Null otherwise.
- UBool negated = FALSE; // TRUE for negated rules.
- UBool integerOnly = FALSE; // TRUE for 'within' rules.
- tokenType digitsType = none; // n | i | v | f constraint.
- AndConstraint *next = nullptr;
- // Internal error status, used for errors that occur during the copy constructor.
- UErrorCode fInternalStatus = U_ZERO_ERROR;
-
- AndConstraint() = default;
+ RuleOp op = AndConstraint::NONE;
+ int32_t opNum = -1; // for mod expressions, the right operand of the mod.
+ int32_t value = -1; // valid for 'is' rules only.
+ UVector32 *rangeList = nullptr; // for 'in', 'within' rules. Null otherwise.
+ UBool negated = FALSE; // TRUE for negated rules.
+ UBool integerOnly = FALSE; // TRUE for 'within' rules.
+ tokenType digitsType = none; // n | i | v | f constraint.
+ AndConstraint *next = nullptr;
+ // Internal error status, used for errors that occur during the copy constructor.
+ UErrorCode fInternalStatus = U_ZERO_ERROR;
+
+ AndConstraint() = default;
AndConstraint(const AndConstraint& other);
virtual ~AndConstraint();
- AndConstraint* add(UErrorCode& status);
+ AndConstraint* add(UErrorCode& status);
// UBool isFulfilled(double number);
- UBool isFulfilled(const IFixedDecimal &number);
+ UBool isFulfilled(const IFixedDecimal &number);
};
class OrConstraint : public UMemory {
public:
- AndConstraint *childNode = nullptr;
- OrConstraint *next = nullptr;
- // Internal error status, used for errors that occur during the copy constructor.
- UErrorCode fInternalStatus = U_ZERO_ERROR;
+ AndConstraint *childNode = nullptr;
+ OrConstraint *next = nullptr;
+ // Internal error status, used for errors that occur during the copy constructor.
+ UErrorCode fInternalStatus = U_ZERO_ERROR;
- OrConstraint() = default;
+ OrConstraint() = default;
OrConstraint(const OrConstraint& other);
virtual ~OrConstraint();
- AndConstraint* add(UErrorCode& status);
+ AndConstraint* add(UErrorCode& status);
// UBool isFulfilled(double number);
- UBool isFulfilled(const IFixedDecimal &number);
+ UBool isFulfilled(const IFixedDecimal &number);
};
class RuleChain : public UMemory {
public:
UnicodeString fKeyword;
- RuleChain *fNext = nullptr;
- OrConstraint *ruleHeader = nullptr;
+ RuleChain *fNext = nullptr;
+ OrConstraint *ruleHeader = nullptr;
UnicodeString fDecimalSamples; // Samples strings from rule source
UnicodeString fIntegerSamples; // without @decimal or @integer, otherwise unprocessed.
- UBool fDecimalSamplesUnbounded = FALSE;
- UBool fIntegerSamplesUnbounded = FALSE;
- // Internal error status, used for errors that occur during the copy constructor.
- UErrorCode fInternalStatus = U_ZERO_ERROR;
+ UBool fDecimalSamplesUnbounded = FALSE;
+ UBool fIntegerSamplesUnbounded = FALSE;
+ // Internal error status, used for errors that occur during the copy constructor.
+ UErrorCode fInternalStatus = U_ZERO_ERROR;
- RuleChain() = default;
+ RuleChain() = default;
RuleChain(const RuleChain& other);
virtual ~RuleChain();
- UnicodeString select(const IFixedDecimal &number) const;
+ UnicodeString select(const IFixedDecimal &number) const;
void dumpRules(UnicodeString& result);
UErrorCode getKeywords(int32_t maxArraySize, UnicodeString *keywords, int32_t& arraySize) const;
UBool isKeyword(const UnicodeString& keyword) const;
@@ -396,8 +396,8 @@ class U_I18N_API PluralAvailableLocalesEnumeration: public StringEnumeration {
virtual int32_t count(UErrorCode& status) const;
private:
UErrorCode fOpenStatus;
- UResourceBundle *fLocales = nullptr;
- UResourceBundle *fRes = nullptr;
+ UResourceBundle *fLocales = nullptr;
+ UResourceBundle *fRes = nullptr;
};
U_NAMESPACE_END
diff --git a/contrib/libs/icu/i18n/quant.cpp b/contrib/libs/icu/i18n/quant.cpp
index ed33933387..22ee5e8311 100644
--- a/contrib/libs/icu/i18n/quant.cpp
+++ b/contrib/libs/icu/i18n/quant.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -47,7 +47,7 @@ Quantifier::~Quantifier() {
/**
* Implement UnicodeFunctor
*/
-Quantifier* Quantifier::clone() const {
+Quantifier* Quantifier::clone() const {
return new Quantifier(*this);
}
diff --git a/contrib/libs/icu/i18n/quant.h b/contrib/libs/icu/i18n/quant.h
index d5aa8e5eee..c81a14c6be 100644
--- a/contrib/libs/icu/i18n/quant.h
+++ b/contrib/libs/icu/i18n/quant.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -45,7 +45,7 @@ class Quantifier : public UnicodeFunctor, public UnicodeMatcher {
* Implement UnicodeFunctor
* @return a copy of the object.
*/
- virtual Quantifier* clone() const;
+ virtual Quantifier* clone() const;
/**
* Implement UnicodeMatcher
diff --git a/contrib/libs/icu/i18n/quantityformatter.cpp b/contrib/libs/icu/i18n/quantityformatter.cpp
index 9c9aa99b67..88d3f5ffac 100644
--- a/contrib/libs/icu/i18n/quantityformatter.cpp
+++ b/contrib/libs/icu/i18n/quantityformatter.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
@@ -24,9 +24,9 @@
#include "unicode/fieldpos.h"
#include "standardplural.h"
#include "uassert.h"
-#include "number_decimalquantity.h"
-#include "number_utypes.h"
-#include "formatted_string_builder.h"
+#include "number_decimalquantity.h"
+#include "number_utypes.h"
+#include "formatted_string_builder.h"
U_NAMESPACE_BEGIN
@@ -153,13 +153,13 @@ StandardPlural::Form QuantityFormatter::selectPlural(
UnicodeString pluralKeyword;
const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt);
if (decFmt != NULL) {
- number::impl::DecimalQuantity dq;
- decFmt->formatToDecimalQuantity(number, dq, status);
+ number::impl::DecimalQuantity dq;
+ decFmt->formatToDecimalQuantity(number, dq, status);
if (U_FAILURE(status)) {
return StandardPlural::OTHER;
}
- pluralKeyword = rules.select(dq);
- decFmt->format(number, formattedNumber, pos, status);
+ pluralKeyword = rules.select(dq);
+ decFmt->format(number, formattedNumber, pos, status);
} else {
if (number.getType() == Formattable::kDouble) {
pluralKeyword = rules.select(number.getDouble());
@@ -176,44 +176,44 @@ StandardPlural::Form QuantityFormatter::selectPlural(
return StandardPlural::orOtherFromString(pluralKeyword);
}
-void QuantityFormatter::formatAndSelect(
- double quantity,
- const NumberFormat& fmt,
- const PluralRules& rules,
- FormattedStringBuilder& output,
- StandardPlural::Form& pluralForm,
- UErrorCode& status) {
- UnicodeString pluralKeyword;
- const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(&fmt);
- if (df != nullptr) {
- number::impl::UFormattedNumberData fn;
- fn.quantity.setToDouble(quantity);
- const number::LocalizedNumberFormatter* lnf = df->toNumberFormatter(status);
- if (U_FAILURE(status)) {
- return;
- }
- lnf->formatImpl(&fn, status);
- if (U_FAILURE(status)) {
- return;
- }
- output = std::move(fn.getStringRef());
- pluralKeyword = rules.select(fn.quantity);
- } else {
- UnicodeString result;
- fmt.format(quantity, result, status);
- if (U_FAILURE(status)) {
- return;
- }
- // This code path is probably RBNF. Use the generic numeric field.
- output.append(result, kGeneralNumericField, status);
- if (U_FAILURE(status)) {
- return;
- }
- pluralKeyword = rules.select(quantity);
- }
- pluralForm = StandardPlural::orOtherFromString(pluralKeyword);
-}
-
+void QuantityFormatter::formatAndSelect(
+ double quantity,
+ const NumberFormat& fmt,
+ const PluralRules& rules,
+ FormattedStringBuilder& output,
+ StandardPlural::Form& pluralForm,
+ UErrorCode& status) {
+ UnicodeString pluralKeyword;
+ const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(&fmt);
+ if (df != nullptr) {
+ number::impl::UFormattedNumberData fn;
+ fn.quantity.setToDouble(quantity);
+ const number::LocalizedNumberFormatter* lnf = df->toNumberFormatter(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ lnf->formatImpl(&fn, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ output = std::move(fn.getStringRef());
+ pluralKeyword = rules.select(fn.quantity);
+ } else {
+ UnicodeString result;
+ fmt.format(quantity, result, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ // This code path is probably RBNF. Use the generic numeric field.
+ output.append(result, kGeneralNumericField, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ pluralKeyword = rules.select(quantity);
+ }
+ pluralForm = StandardPlural::orOtherFromString(pluralKeyword);
+}
+
UnicodeString &QuantityFormatter::format(
const SimpleFormatter &pattern,
const UnicodeString &value,
diff --git a/contrib/libs/icu/i18n/quantityformatter.h b/contrib/libs/icu/i18n/quantityformatter.h
index daaef4f060..3089f38e06 100644
--- a/contrib/libs/icu/i18n/quantityformatter.h
+++ b/contrib/libs/icu/i18n/quantityformatter.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
@@ -26,7 +26,7 @@ class PluralRules;
class NumberFormat;
class Formattable;
class FieldPosition;
-class FormattedStringBuilder;
+class FormattedStringBuilder;
/**
* A plural aware formatter that is good for expressing a single quantity and
@@ -112,7 +112,7 @@ public:
/**
* Selects the standard plural form for the number/formatter/rules.
- * TODO(13591): Remove this method.
+ * TODO(13591): Remove this method.
*/
static StandardPlural::Form selectPlural(
const Formattable &number,
@@ -123,29 +123,29 @@ public:
UErrorCode &status);
/**
- * Formats a quantity and selects its plural form. The output is appended
- * to a FormattedStringBuilder in order to retain field information.
- *
- * @param quantity The number to format.
- * @param fmt The formatter to use to format the number.
- * @param rules The rules to use to select the plural form of the
- * formatted number.
- * @param output Where to append the result of the format operation.
- * @param pluralForm Output variable populated with the plural form of the
- * formatted number.
- * @param status Set if an error occurs.
- */
- static void formatAndSelect(
- double quantity,
- const NumberFormat& fmt,
- const PluralRules& rules,
- FormattedStringBuilder& output,
- StandardPlural::Form& pluralForm,
- UErrorCode& status);
-
- /**
+ * Formats a quantity and selects its plural form. The output is appended
+ * to a FormattedStringBuilder in order to retain field information.
+ *
+ * @param quantity The number to format.
+ * @param fmt The formatter to use to format the number.
+ * @param rules The rules to use to select the plural form of the
+ * formatted number.
+ * @param output Where to append the result of the format operation.
+ * @param pluralForm Output variable populated with the plural form of the
+ * formatted number.
+ * @param status Set if an error occurs.
+ */
+ static void formatAndSelect(
+ double quantity,
+ const NumberFormat& fmt,
+ const PluralRules& rules,
+ FormattedStringBuilder& output,
+ StandardPlural::Form& pluralForm,
+ UErrorCode& status);
+
+ /**
* Formats the pattern with the value and adjusts the FieldPosition.
- * TODO: Remove?
+ * TODO: Remove?
*/
static UnicodeString &format(
const SimpleFormatter &pattern,
diff --git a/contrib/libs/icu/i18n/rbnf.cpp b/contrib/libs/icu/i18n/rbnf.cpp
index 17319fb6d5..0491082c7c 100644
--- a/contrib/libs/icu/i18n/rbnf.cpp
+++ b/contrib/libs/icu/i18n/rbnf.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -27,14 +27,14 @@
#include "unicode/udata.h"
#include "unicode/udisplaycontext.h"
#include "unicode/brkiter.h"
-#include "unicode/ucasemap.h"
+#include "unicode/ucasemap.h"
#include "cmemory.h"
#include "cstring.h"
#include "patternprops.h"
#include "uresimp.h"
-#include "nfrs.h"
-#include "number_decimalquantity.h"
+#include "nfrs.h"
+#include "number_decimalquantity.h"
// debugging
// #define RBNF_DEBUG
@@ -68,8 +68,8 @@ static const UChar gSemiPercent[] =
U_NAMESPACE_BEGIN
-using number::impl::DecimalQuantity;
-
+using number::impl::DecimalQuantity;
+
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedNumberFormat)
/*
@@ -318,34 +318,34 @@ public:
private:
- inline void inc(void) {
- ++p;
- ch = 0xffff;
- }
- inline UBool checkInc(UChar c) {
- if (p < e && (ch == c || *p == c)) {
- inc();
- return TRUE;
- }
- return FALSE;
- }
- inline UBool check(UChar c) {
- return p < e && (ch == c || *p == c);
- }
- inline void skipWhitespace(void) {
- while (p < e && PatternProps::isWhiteSpace(ch != 0xffff ? ch : *p)) {
- inc();
- }
- }
- inline UBool inList(UChar c, const UChar* list) const {
- if (*list == SPACE && PatternProps::isWhiteSpace(c)) {
- return TRUE;
- }
- while (*list && *list != c) {
- ++list;
- }
- return *list == c;
- }
+ inline void inc(void) {
+ ++p;
+ ch = 0xffff;
+ }
+ inline UBool checkInc(UChar c) {
+ if (p < e && (ch == c || *p == c)) {
+ inc();
+ return TRUE;
+ }
+ return FALSE;
+ }
+ inline UBool check(UChar c) {
+ return p < e && (ch == c || *p == c);
+ }
+ inline void skipWhitespace(void) {
+ while (p < e && PatternProps::isWhiteSpace(ch != 0xffff ? ch : *p)) {
+ inc();
+ }
+ }
+ inline UBool inList(UChar c, const UChar* list) const {
+ if (*list == SPACE && PatternProps::isWhiteSpace(c)) {
+ return TRUE;
+ }
+ while (*list && *list != c) {
+ ++list;
+ }
+ return *list == c;
+ }
void parseError(const char* msg);
StringLocalizationInfo* doParse(void);
@@ -355,16 +355,16 @@ private:
};
#ifdef RBNF_DEBUG
-#define ERROR(msg) UPRV_BLOCK_MACRO_BEGIN { \
- parseError(msg); \
- return NULL; \
-} UPRV_BLOCK_MACRO_END
+#define ERROR(msg) UPRV_BLOCK_MACRO_BEGIN { \
+ parseError(msg); \
+ return NULL; \
+} UPRV_BLOCK_MACRO_END
#define EXPLANATION_ARG explanationArg
#else
-#define ERROR(msg) UPRV_BLOCK_MACRO_BEGIN { \
- parseError(NULL); \
- return NULL; \
-} UPRV_BLOCK_MACRO_END
+#define ERROR(msg) UPRV_BLOCK_MACRO_BEGIN { \
+ parseError(NULL); \
+ return NULL; \
+} UPRV_BLOCK_MACRO_END
#define EXPLANATION_ARG
#endif
@@ -686,7 +686,7 @@ StringLocalizationInfo::getDisplayName(int32_t localeIndex, int32_t ruleIndex) c
RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
const UnicodeString& locs,
const Locale& alocale, UParseError& perror, UErrorCode& status)
- : fRuleSets(NULL)
+ : fRuleSets(NULL)
, ruleSetDescriptions(NULL)
, numRuleSets(0)
, defaultRuleSet(NULL)
@@ -695,7 +695,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
, decimalFormatSymbols(NULL)
, defaultInfinityRule(NULL)
, defaultNaNRule(NULL)
- , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
+ , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
@@ -711,7 +711,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
const UnicodeString& locs,
UParseError& perror, UErrorCode& status)
- : fRuleSets(NULL)
+ : fRuleSets(NULL)
, ruleSetDescriptions(NULL)
, numRuleSets(0)
, defaultRuleSet(NULL)
@@ -720,7 +720,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
, decimalFormatSymbols(NULL)
, defaultInfinityRule(NULL)
, defaultNaNRule(NULL)
- , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
+ , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
@@ -736,7 +736,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
LocalizationInfo* info,
const Locale& alocale, UParseError& perror, UErrorCode& status)
- : fRuleSets(NULL)
+ : fRuleSets(NULL)
, ruleSetDescriptions(NULL)
, numRuleSets(0)
, defaultRuleSet(NULL)
@@ -745,7 +745,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
, decimalFormatSymbols(NULL)
, defaultInfinityRule(NULL)
, defaultNaNRule(NULL)
- , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
+ , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
@@ -760,7 +760,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
UParseError& perror,
UErrorCode& status)
- : fRuleSets(NULL)
+ : fRuleSets(NULL)
, ruleSetDescriptions(NULL)
, numRuleSets(0)
, defaultRuleSet(NULL)
@@ -769,7 +769,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
, decimalFormatSymbols(NULL)
, defaultInfinityRule(NULL)
, defaultNaNRule(NULL)
- , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
+ , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
@@ -785,7 +785,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
const Locale& aLocale,
UParseError& perror,
UErrorCode& status)
- : fRuleSets(NULL)
+ : fRuleSets(NULL)
, ruleSetDescriptions(NULL)
, numRuleSets(0)
, defaultRuleSet(NULL)
@@ -794,7 +794,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
, decimalFormatSymbols(NULL)
, defaultInfinityRule(NULL)
, defaultNaNRule(NULL)
- , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
+ , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
@@ -807,7 +807,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
}
RuleBasedNumberFormat::RuleBasedNumberFormat(URBNFRuleSetTag tag, const Locale& alocale, UErrorCode& status)
- : fRuleSets(NULL)
+ : fRuleSets(NULL)
, ruleSetDescriptions(NULL)
, numRuleSets(0)
, defaultRuleSet(NULL)
@@ -816,7 +816,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(URBNFRuleSetTag tag, const Locale&
, decimalFormatSymbols(NULL)
, defaultInfinityRule(NULL)
, defaultNaNRule(NULL)
- , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
+ , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
@@ -874,7 +874,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(URBNFRuleSetTag tag, const Locale&
RuleBasedNumberFormat::RuleBasedNumberFormat(const RuleBasedNumberFormat& rhs)
: NumberFormat(rhs)
- , fRuleSets(NULL)
+ , fRuleSets(NULL)
, ruleSetDescriptions(NULL)
, numRuleSets(0)
, defaultRuleSet(NULL)
@@ -883,7 +883,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const RuleBasedNumberFormat& rhs)
, decimalFormatSymbols(NULL)
, defaultInfinityRule(NULL)
, defaultNaNRule(NULL)
- , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
+ , fRoundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
@@ -913,7 +913,7 @@ RuleBasedNumberFormat::operator=(const RuleBasedNumberFormat& rhs)
setDecimalFormatSymbols(*rhs.getDecimalFormatSymbols());
init(rhs.originalDescription, rhs.localizations ? rhs.localizations->ref() : NULL, perror, status);
setDefaultRuleSet(rhs.getDefaultRuleSetName(), status);
- setRoundingMode(rhs.getRoundingMode());
+ setRoundingMode(rhs.getRoundingMode());
capitalizationInfoSet = rhs.capitalizationInfoSet;
capitalizationForUIListMenu = rhs.capitalizationForUIListMenu;
@@ -930,8 +930,8 @@ RuleBasedNumberFormat::~RuleBasedNumberFormat()
dispose();
}
-RuleBasedNumberFormat*
-RuleBasedNumberFormat::clone() const
+RuleBasedNumberFormat*
+RuleBasedNumberFormat::clone() const
{
return new RuleBasedNumberFormat(*this);
}
@@ -956,8 +956,8 @@ RuleBasedNumberFormat::operator==(const Format& other) const
? FALSE
: *localizations == rhs.localizations))) {
- NFRuleSet** p = fRuleSets;
- NFRuleSet** q = rhs.fRuleSets;
+ NFRuleSet** p = fRuleSets;
+ NFRuleSet** q = rhs.fRuleSets;
if (p == NULL) {
return q == NULL;
} else if (q == NULL) {
@@ -978,8 +978,8 @@ UnicodeString
RuleBasedNumberFormat::getRules() const
{
UnicodeString result;
- if (fRuleSets != NULL) {
- for (NFRuleSet** p = fRuleSets; *p; ++p) {
+ if (fRuleSets != NULL) {
+ for (NFRuleSet** p = fRuleSets; *p; ++p) {
(*p)->appendRules(result);
}
}
@@ -993,9 +993,9 @@ RuleBasedNumberFormat::getRuleSetName(int32_t index) const
UnicodeString string(TRUE, localizations->getRuleSetName(index), (int32_t)-1);
return string;
}
- else if (fRuleSets) {
+ else if (fRuleSets) {
UnicodeString result;
- for (NFRuleSet** p = fRuleSets; *p; ++p) {
+ for (NFRuleSet** p = fRuleSets; *p; ++p) {
NFRuleSet* rs = *p;
if (rs->isPublic()) {
if (--index == -1) {
@@ -1016,8 +1016,8 @@ RuleBasedNumberFormat::getNumberOfRuleSetNames() const
if (localizations) {
result = localizations->getNumberOfRuleSets();
}
- else if (fRuleSets) {
- for (NFRuleSet** p = fRuleSets; *p; ++p) {
+ else if (fRuleSets) {
+ for (NFRuleSet** p = fRuleSets; *p; ++p) {
if ((**p).isPublic()) {
++result;
}
@@ -1104,8 +1104,8 @@ RuleBasedNumberFormat::getRuleSetDisplayName(const UnicodeString& ruleSetName, c
NFRuleSet*
RuleBasedNumberFormat::findRuleSet(const UnicodeString& name, UErrorCode& status) const
{
- if (U_SUCCESS(status) && fRuleSets) {
- for (NFRuleSet** p = fRuleSets; *p; ++p) {
+ if (U_SUCCESS(status) && fRuleSets) {
+ for (NFRuleSet** p = fRuleSets; *p; ++p) {
NFRuleSet* rs = *p;
if (rs->isNamed(name)) {
return rs;
@@ -1117,49 +1117,49 @@ RuleBasedNumberFormat::findRuleSet(const UnicodeString& name, UErrorCode& status
}
UnicodeString&
-RuleBasedNumberFormat::format(const DecimalQuantity &number,
- UnicodeString& appendTo,
- FieldPosition& pos,
- UErrorCode &status) const {
- if (U_FAILURE(status)) {
- return appendTo;
- }
- DecimalQuantity copy(number);
- if (copy.fitsInLong()) {
- format(number.toLong(), appendTo, pos, status);
- }
- else {
- 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.
- // The DecimalFormat will provide more accurate results.
-
- // TODO this section should probably be optimized. The DecimalFormat is shared in ICU4J.
- LocalPointer<NumberFormat> decimalFormat(NumberFormat::createInstance(locale, UNUM_DECIMAL, status), status);
- if (decimalFormat.isNull()) {
- return appendTo;
- }
- Formattable f;
- LocalPointer<DecimalQuantity> decimalQuantity(new DecimalQuantity(number), status);
- if (decimalQuantity.isNull()) {
- return appendTo;
- }
- f.adoptDecimalQuantity(decimalQuantity.orphan()); // f now owns decimalQuantity.
- decimalFormat->format(f, appendTo, pos, status);
- }
- }
- return appendTo;
-}
-
-UnicodeString&
+RuleBasedNumberFormat::format(const DecimalQuantity &number,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode &status) const {
+ if (U_FAILURE(status)) {
+ return appendTo;
+ }
+ DecimalQuantity copy(number);
+ if (copy.fitsInLong()) {
+ format(number.toLong(), appendTo, pos, status);
+ }
+ else {
+ 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.
+ // The DecimalFormat will provide more accurate results.
+
+ // TODO this section should probably be optimized. The DecimalFormat is shared in ICU4J.
+ LocalPointer<NumberFormat> decimalFormat(NumberFormat::createInstance(locale, UNUM_DECIMAL, status), status);
+ if (decimalFormat.isNull()) {
+ return appendTo;
+ }
+ Formattable f;
+ LocalPointer<DecimalQuantity> decimalQuantity(new DecimalQuantity(number), status);
+ if (decimalQuantity.isNull()) {
+ return appendTo;
+ }
+ f.adoptDecimalQuantity(decimalQuantity.orphan()); // f now owns decimalQuantity.
+ decimalFormat->format(f, appendTo, pos, status);
+ }
+ }
+ return appendTo;
+}
+
+UnicodeString&
RuleBasedNumberFormat::format(int32_t number,
UnicodeString& toAppendTo,
- FieldPosition& pos) const
+ FieldPosition& pos) const
{
- return format((int64_t)number, toAppendTo, pos);
+ return format((int64_t)number, toAppendTo, pos);
}
@@ -1170,7 +1170,7 @@ RuleBasedNumberFormat::format(int64_t number,
{
if (defaultRuleSet) {
UErrorCode status = U_ZERO_ERROR;
- format(number, defaultRuleSet, toAppendTo, status);
+ format(number, defaultRuleSet, toAppendTo, status);
}
return toAppendTo;
}
@@ -1181,11 +1181,11 @@ RuleBasedNumberFormat::format(double number,
UnicodeString& toAppendTo,
FieldPosition& /* pos */) const
{
- UErrorCode status = U_ZERO_ERROR;
+ UErrorCode status = U_ZERO_ERROR;
if (defaultRuleSet) {
- format(number, *defaultRuleSet, toAppendTo, status);
+ format(number, *defaultRuleSet, toAppendTo, status);
}
- return toAppendTo;
+ return toAppendTo;
}
@@ -1193,17 +1193,17 @@ UnicodeString&
RuleBasedNumberFormat::format(int32_t number,
const UnicodeString& ruleSetName,
UnicodeString& toAppendTo,
- FieldPosition& pos,
- UErrorCode& status) const
-{
- return format((int64_t)number, ruleSetName, toAppendTo, pos, status);
-}
-
-
-UnicodeString&
-RuleBasedNumberFormat::format(int64_t number,
- const UnicodeString& ruleSetName,
- UnicodeString& toAppendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const
+{
+ return format((int64_t)number, ruleSetName, toAppendTo, pos, status);
+}
+
+
+UnicodeString&
+RuleBasedNumberFormat::format(int64_t number,
+ const UnicodeString& ruleSetName,
+ UnicodeString& toAppendTo,
FieldPosition& /* pos */,
UErrorCode& status) const
{
@@ -1214,7 +1214,7 @@ RuleBasedNumberFormat::format(int64_t number,
} else {
NFRuleSet *rs = findRuleSet(ruleSetName, status);
if (rs) {
- format(number, rs, toAppendTo, status);
+ format(number, rs, toAppendTo, status);
}
}
}
@@ -1223,7 +1223,7 @@ RuleBasedNumberFormat::format(int64_t number,
UnicodeString&
-RuleBasedNumberFormat::format(double number,
+RuleBasedNumberFormat::format(double number,
const UnicodeString& ruleSetName,
UnicodeString& toAppendTo,
FieldPosition& /* pos */,
@@ -1236,100 +1236,100 @@ RuleBasedNumberFormat::format(double number,
} else {
NFRuleSet *rs = findRuleSet(ruleSetName, status);
if (rs) {
- format(number, *rs, toAppendTo, status);
+ format(number, *rs, toAppendTo, status);
}
}
}
return toAppendTo;
}
-void
+void
RuleBasedNumberFormat::format(double number,
- NFRuleSet& rs,
+ NFRuleSet& rs,
UnicodeString& toAppendTo,
UErrorCode& status) const
{
- int32_t startPos = toAppendTo.length();
- if (getRoundingMode() != DecimalFormat::ERoundingMode::kRoundUnnecessary && !uprv_isNaN(number) && !uprv_isInfinite(number)) {
- DecimalQuantity digitList;
- digitList.setToDouble(number);
- digitList.roundToMagnitude(
- -getMaximumFractionDigits(),
- static_cast<UNumberFormatRoundingMode>(getRoundingMode()),
- status);
- number = digitList.toDouble();
- }
- rs.format(number, toAppendTo, toAppendTo.length(), 0, status);
- adjustForCapitalizationContext(startPos, toAppendTo, status);
-}
-
-/**
- * Bottleneck through which all the public format() methods
- * that take a long pass. By the time we get here, we know
- * which rule set we're using to do the formatting.
- * @param number The number to format
- * @param ruleSet The rule set to use to format the number
- * @return The text that resulted from formatting the number
- */
-UnicodeString&
-RuleBasedNumberFormat::format(int64_t number, NFRuleSet *ruleSet, UnicodeString& toAppendTo, UErrorCode& status) const
-{
- // all API format() routines that take a double vector through
- // here. We have these two identical functions-- one taking a
- // double and one taking a long-- the couple digits of precision
- // that long has but double doesn't (both types are 8 bytes long,
- // but double has to borrow some of the mantissa bits to hold
- // the exponent).
- // Create an empty string buffer where the result will
- // be built, and pass it to the rule set (along with an insertion
- // position of 0 and the number being formatted) to the rule set
- // for formatting
-
+ int32_t startPos = toAppendTo.length();
+ if (getRoundingMode() != DecimalFormat::ERoundingMode::kRoundUnnecessary && !uprv_isNaN(number) && !uprv_isInfinite(number)) {
+ DecimalQuantity digitList;
+ digitList.setToDouble(number);
+ digitList.roundToMagnitude(
+ -getMaximumFractionDigits(),
+ static_cast<UNumberFormatRoundingMode>(getRoundingMode()),
+ status);
+ number = digitList.toDouble();
+ }
+ rs.format(number, toAppendTo, toAppendTo.length(), 0, status);
+ adjustForCapitalizationContext(startPos, toAppendTo, status);
+}
+
+/**
+ * Bottleneck through which all the public format() methods
+ * that take a long pass. By the time we get here, we know
+ * which rule set we're using to do the formatting.
+ * @param number The number to format
+ * @param ruleSet The rule set to use to format the number
+ * @return The text that resulted from formatting the number
+ */
+UnicodeString&
+RuleBasedNumberFormat::format(int64_t number, NFRuleSet *ruleSet, UnicodeString& toAppendTo, UErrorCode& status) const
+{
+ // all API format() routines that take a double vector through
+ // here. We have these two identical functions-- one taking a
+ // double and one taking a long-- the couple digits of precision
+ // that long has but double doesn't (both types are 8 bytes long,
+ // but double has to borrow some of the mantissa bits to hold
+ // the exponent).
+ // Create an empty string buffer where the result will
+ // be built, and pass it to the rule set (along with an insertion
+ // position of 0 and the number being formatted) to the rule set
+ // for formatting
+
if (U_SUCCESS(status)) {
- if (number == U_INT64_MIN) {
- // We can't handle this value right now. Provide an accurate default value.
-
- // TODO this section should probably be optimized. The DecimalFormat is shared in ICU4J.
- NumberFormat *decimalFormat = NumberFormat::createInstance(locale, UNUM_DECIMAL, status);
- if (decimalFormat == nullptr) {
- return toAppendTo;
+ if (number == U_INT64_MIN) {
+ // We can't handle this value right now. Provide an accurate default value.
+
+ // TODO this section should probably be optimized. The DecimalFormat is shared in ICU4J.
+ NumberFormat *decimalFormat = NumberFormat::createInstance(locale, UNUM_DECIMAL, status);
+ if (decimalFormat == nullptr) {
+ return toAppendTo;
}
- Formattable f;
- FieldPosition pos(FieldPosition::DONT_CARE);
- DecimalQuantity *decimalQuantity = new DecimalQuantity();
- if (decimalQuantity == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- delete decimalFormat;
- return toAppendTo;
- }
- decimalQuantity->setToLong(number);
- f.adoptDecimalQuantity(decimalQuantity); // f now owns decimalQuantity.
- decimalFormat->format(f, toAppendTo, pos, status);
- delete decimalFormat;
- }
- else {
- int32_t startPos = toAppendTo.length();
- ruleSet->format(number, toAppendTo, toAppendTo.length(), 0, status);
- adjustForCapitalizationContext(startPos, toAppendTo, status);
- }
+ Formattable f;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ DecimalQuantity *decimalQuantity = new DecimalQuantity();
+ if (decimalQuantity == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ delete decimalFormat;
+ return toAppendTo;
+ }
+ decimalQuantity->setToLong(number);
+ f.adoptDecimalQuantity(decimalQuantity); // f now owns decimalQuantity.
+ decimalFormat->format(f, toAppendTo, pos, status);
+ delete decimalFormat;
+ }
+ else {
+ int32_t startPos = toAppendTo.length();
+ ruleSet->format(number, toAppendTo, toAppendTo.length(), 0, status);
+ adjustForCapitalizationContext(startPos, toAppendTo, status);
+ }
}
return toAppendTo;
}
UnicodeString&
RuleBasedNumberFormat::adjustForCapitalizationContext(int32_t startPos,
- UnicodeString& currentResult,
- UErrorCode& status) const
+ UnicodeString& currentResult,
+ UErrorCode& status) const
{
#if !UCONFIG_NO_BREAK_ITERATION
- UDisplayContext capitalizationContext = getContext(UDISPCTX_TYPE_CAPITALIZATION, status);
- if (capitalizationContext != UDISPCTX_CAPITALIZATION_NONE && startPos == 0 && currentResult.length() > 0) {
+ UDisplayContext capitalizationContext = getContext(UDISPCTX_TYPE_CAPITALIZATION, status);
+ if (capitalizationContext != UDISPCTX_CAPITALIZATION_NONE && startPos == 0 && currentResult.length() > 0) {
// capitalize currentResult according to context
UChar32 ch = currentResult.char32At(0);
- if (u_islower(ch) && U_SUCCESS(status) && capitalizationBrkIter != NULL &&
- ( capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
- (capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && capitalizationForUIListMenu) ||
- (capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_STANDALONE && capitalizationForStandAlone)) ) {
+ if (u_islower(ch) && U_SUCCESS(status) && capitalizationBrkIter != NULL &&
+ ( capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
+ (capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && capitalizationForUIListMenu) ||
+ (capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_STANDALONE && capitalizationForStandAlone)) ) {
// titlecase first word of currentResult, here use sentence iterator unlike current implementations
// in LocaleDisplayNamesImpl::adjustForUsageAndContext and RelativeDateFormat::format
currentResult.toTitle(capitalizationBrkIter, locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
@@ -1345,7 +1345,7 @@ RuleBasedNumberFormat::parse(const UnicodeString& text,
Formattable& result,
ParsePosition& parsePosition) const
{
- if (!fRuleSets) {
+ if (!fRuleSets) {
parsePosition.setErrorIndex(0);
return;
}
@@ -1356,13 +1356,13 @@ RuleBasedNumberFormat::parse(const UnicodeString& text,
ParsePosition high_pp(0);
Formattable high_result;
- for (NFRuleSet** p = fRuleSets; *p; ++p) {
+ for (NFRuleSet** p = fRuleSets; *p; ++p) {
NFRuleSet *rp = *p;
if (rp->isPublic() && rp->isParseable()) {
ParsePosition working_pp(0);
Formattable working_result;
- rp->parse(workingText, working_pp, kMaxDouble, 0, working_result);
+ rp->parse(workingText, working_pp, kMaxDouble, 0, working_result);
if (working_pp.getIndex() > high_pp.getIndex()) {
high_pp = working_pp;
high_result = working_result;
@@ -1444,7 +1444,7 @@ void
RuleBasedNumberFormat::initDefaultRuleSet()
{
defaultRuleSet = NULL;
- if (!fRuleSets) {
+ if (!fRuleSets) {
return;
}
@@ -1452,7 +1452,7 @@ RuleBasedNumberFormat::initDefaultRuleSet()
const UnicodeString ordinal(UNICODE_STRING_SIMPLE("%digits-ordinal"));
const UnicodeString duration(UNICODE_STRING_SIMPLE("%duration"));
- NFRuleSet**p = &fRuleSets[0];
+ NFRuleSet**p = &fRuleSets[0];
while (*p) {
if ((*p)->isNamed(spellout) || (*p)->isNamed(ordinal) || (*p)->isNamed(duration)) {
defaultRuleSet = *p;
@@ -1464,7 +1464,7 @@ RuleBasedNumberFormat::initDefaultRuleSet()
defaultRuleSet = *--p;
if (!defaultRuleSet->isPublic()) {
- while (p != fRuleSets) {
+ while (p != fRuleSets) {
if ((*--p)->isPublic()) {
defaultRuleSet = *p;
break;
@@ -1534,7 +1534,7 @@ RuleBasedNumberFormat::init(const UnicodeString& rules, LocalizationInfo* locali
// from the description
lenientParseRules = new UnicodeString();
/* test for NULL */
- if (lenientParseRules == nullptr) {
+ if (lenientParseRules == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
@@ -1555,15 +1555,15 @@ RuleBasedNumberFormat::init(const UnicodeString& rules, LocalizationInfo* locali
++numRuleSets;
// our rule list is an array of the appropriate size
- fRuleSets = (NFRuleSet **)uprv_malloc((numRuleSets + 1) * sizeof(NFRuleSet *));
+ fRuleSets = (NFRuleSet **)uprv_malloc((numRuleSets + 1) * sizeof(NFRuleSet *));
/* test for NULL */
- if (fRuleSets == 0) {
+ if (fRuleSets == 0) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
for (int i = 0; i <= numRuleSets; ++i) {
- fRuleSets[i] = NULL;
+ fRuleSets[i] = NULL;
}
// divide up the descriptions into individual rule-set descriptions
@@ -1579,7 +1579,7 @@ RuleBasedNumberFormat::init(const UnicodeString& rules, LocalizationInfo* locali
}
ruleSetDescriptions = new UnicodeString[numRuleSets];
- if (ruleSetDescriptions == nullptr) {
+ if (ruleSetDescriptions == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
@@ -1589,8 +1589,8 @@ RuleBasedNumberFormat::init(const UnicodeString& rules, LocalizationInfo* locali
int32_t start = 0;
for (int32_t p = description.indexOf(gSemiPercent, 2, 0); p != -1; p = description.indexOf(gSemiPercent, 2, start)) {
ruleSetDescriptions[curRuleSet].setTo(description, start, p + 1 - start);
- fRuleSets[curRuleSet] = new NFRuleSet(this, ruleSetDescriptions, curRuleSet, status);
- if (fRuleSets[curRuleSet] == nullptr) {
+ fRuleSets[curRuleSet] = new NFRuleSet(this, ruleSetDescriptions, curRuleSet, status);
+ if (fRuleSets[curRuleSet] == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
@@ -1598,8 +1598,8 @@ RuleBasedNumberFormat::init(const UnicodeString& rules, LocalizationInfo* locali
start = p + 1;
}
ruleSetDescriptions[curRuleSet].setTo(description, start, description.length() - start);
- fRuleSets[curRuleSet] = new NFRuleSet(this, ruleSetDescriptions, curRuleSet, status);
- if (fRuleSets[curRuleSet] == nullptr) {
+ fRuleSets[curRuleSet] = new NFRuleSet(this, ruleSetDescriptions, curRuleSet, status);
+ if (fRuleSets[curRuleSet] == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
@@ -1617,11 +1617,11 @@ RuleBasedNumberFormat::init(const UnicodeString& rules, LocalizationInfo* locali
initDefaultRuleSet();
// finally, we can go back through the temporary descriptions
- // list and finish setting up the substructure (and we throw
+ // list and finish setting up the substructure (and we throw
// away the temporary descriptions as we go)
{
for (int i = 0; i < numRuleSets; i++) {
- fRuleSets[i]->parseRules(ruleSetDescriptions[i], status);
+ fRuleSets[i]->parseRules(ruleSetDescriptions[i], status);
}
}
@@ -1667,7 +1667,7 @@ RuleBasedNumberFormat::setContext(UDisplayContext value, UErrorCode& status)
if ( capitalizationBrkIter == NULL && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
(value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && capitalizationForUIListMenu) ||
(value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE && capitalizationForStandAlone)) ) {
- status = U_ZERO_ERROR;
+ status = U_ZERO_ERROR;
capitalizationBrkIter = BreakIterator::createSentenceInstance(locale, status);
if (U_FAILURE(status)) {
delete capitalizationBrkIter;
@@ -1691,8 +1691,8 @@ RuleBasedNumberFormat::initCapitalizationContextInfo(const Locale& thelocale)
int32_t len = 0;
const int32_t * intVector = ures_getIntVector(rb, &len, &status);
if (U_SUCCESS(status) && intVector != NULL && len >= 2) {
- capitalizationForUIListMenu = static_cast<UBool>(intVector[0]);
- capitalizationForStandAlone = static_cast<UBool>(intVector[1]);
+ capitalizationForUIListMenu = static_cast<UBool>(intVector[0]);
+ capitalizationForStandAlone = static_cast<UBool>(intVector[1]);
}
}
ures_close(rb);
@@ -1727,7 +1727,7 @@ RuleBasedNumberFormat::stripWhitespace(UnicodeString& description)
start = p + 1;
}
- // when we get here, we've seeked off the end of the string, and
+ // when we get here, we've seeked off the end of the string, and
// we terminate the loop (we continue until *start* is -1 rather
// than until *p* is -1, because otherwise we'd miss the last
// rule in the description)
@@ -1743,12 +1743,12 @@ RuleBasedNumberFormat::stripWhitespace(UnicodeString& description)
void
RuleBasedNumberFormat::dispose()
{
- if (fRuleSets) {
- for (NFRuleSet** p = fRuleSets; *p; ++p) {
+ if (fRuleSets) {
+ for (NFRuleSet** p = fRuleSets; *p; ++p) {
delete *p;
}
- uprv_free(fRuleSets);
- fRuleSets = NULL;
+ uprv_free(fRuleSets);
+ fRuleSets = NULL;
}
if (ruleSetDescriptions) {
@@ -1798,7 +1798,7 @@ const RuleBasedCollator*
RuleBasedNumberFormat::getCollator() const
{
#if !UCONFIG_NO_COLLATION
- if (!fRuleSets) {
+ if (!fRuleSets) {
return NULL;
}
@@ -1807,7 +1807,7 @@ RuleBasedNumberFormat::getCollator() const
// create a default collator based on the formatter's locale,
// then pull out that collator's rules, append any additional
// rules specified in the description, and create a _new_
- // collator based on the combination of those rules
+ // collator based on the combination of those rules
UErrorCode status = U_ZERO_ERROR;
@@ -1850,10 +1850,10 @@ RuleBasedNumberFormat::initializeDecimalFormatSymbols(UErrorCode &status)
// lazy-evaluate the DecimalFormatSymbols object. This object
// is shared by all DecimalFormat instances belonging to this
// formatter
- if (decimalFormatSymbols == nullptr) {
- LocalPointer<DecimalFormatSymbols> temp(new DecimalFormatSymbols(locale, status), status);
+ if (decimalFormatSymbols == nullptr) {
+ LocalPointer<DecimalFormatSymbols> temp(new DecimalFormatSymbols(locale, status), status);
if (U_SUCCESS(status)) {
- decimalFormatSymbols = temp.orphan();
+ decimalFormatSymbols = temp.orphan();
}
}
return decimalFormatSymbols;
@@ -1873,14 +1873,14 @@ NFRule*
RuleBasedNumberFormat::initializeDefaultInfinityRule(UErrorCode &status)
{
if (U_FAILURE(status)) {
- return nullptr;
+ return nullptr;
}
if (defaultInfinityRule == NULL) {
UnicodeString rule(UNICODE_STRING_SIMPLE("Inf: "));
rule.append(getDecimalFormatSymbols()->getSymbol(DecimalFormatSymbols::kInfinitySymbol));
- LocalPointer<NFRule> temp(new NFRule(this, rule, status), status);
+ LocalPointer<NFRule> temp(new NFRule(this, rule, status), status);
if (U_SUCCESS(status)) {
- defaultInfinityRule = temp.orphan();
+ defaultInfinityRule = temp.orphan();
}
}
return defaultInfinityRule;
@@ -1896,14 +1896,14 @@ NFRule*
RuleBasedNumberFormat::initializeDefaultNaNRule(UErrorCode &status)
{
if (U_FAILURE(status)) {
- return nullptr;
+ return nullptr;
}
- if (defaultNaNRule == nullptr) {
+ if (defaultNaNRule == nullptr) {
UnicodeString rule(UNICODE_STRING_SIMPLE("NaN: "));
rule.append(getDecimalFormatSymbols()->getSymbol(DecimalFormatSymbols::kNaNSymbol));
- LocalPointer<NFRule> temp(new NFRule(this, rule, status), status);
+ LocalPointer<NFRule> temp(new NFRule(this, rule, status), status);
if (U_SUCCESS(status)) {
- defaultNaNRule = temp.orphan();
+ defaultNaNRule = temp.orphan();
}
}
return defaultNaNRule;
@@ -1941,15 +1941,15 @@ RuleBasedNumberFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsTo
defaultNaNRule = NULL;
initializeDefaultNaNRule(status); // Reset with the new DecimalFormatSymbols
- if (fRuleSets) {
+ if (fRuleSets) {
for (int32_t i = 0; i < numRuleSets; i++) {
- fRuleSets[i]->setDecimalFormatSymbols(*symbolsToAdopt, status);
+ fRuleSets[i]->setDecimalFormatSymbols(*symbolsToAdopt, status);
}
}
}
}
-// Setting the symbols is equivalent to adopting a newly created localized symbols.
+// Setting the symbols is equivalent to adopting a newly created localized symbols.
void
RuleBasedNumberFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols)
{
@@ -1961,30 +1961,30 @@ RuleBasedNumberFormat::createPluralFormat(UPluralType pluralType,
const UnicodeString &pattern,
UErrorCode& status) const
{
- auto *pf = new PluralFormat(locale, pluralType, pattern, status);
- if (pf == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
- return pf;
-}
-
-/**
- * Get the rounding mode.
- * @return A rounding mode
- */
-DecimalFormat::ERoundingMode RuleBasedNumberFormat::getRoundingMode() const {
- return fRoundingMode;
-}
-
-/**
- * Set the rounding mode. This has no effect unless the rounding
- * increment is greater than zero.
- * @param roundingMode A rounding mode
- */
-void RuleBasedNumberFormat::setRoundingMode(DecimalFormat::ERoundingMode roundingMode) {
- fRoundingMode = roundingMode;
-}
-
+ auto *pf = new PluralFormat(locale, pluralType, pattern, status);
+ if (pf == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return pf;
+}
+
+/**
+ * Get the rounding mode.
+ * @return A rounding mode
+ */
+DecimalFormat::ERoundingMode RuleBasedNumberFormat::getRoundingMode() const {
+ return fRoundingMode;
+}
+
+/**
+ * Set the rounding mode. This has no effect unless the rounding
+ * increment is greater than zero.
+ * @param roundingMode A rounding mode
+ */
+void RuleBasedNumberFormat::setRoundingMode(DecimalFormat::ERoundingMode roundingMode) {
+ fRoundingMode = roundingMode;
+}
+
U_NAMESPACE_END
/* U_HAVE_RBNF */
diff --git a/contrib/libs/icu/i18n/rbt.cpp b/contrib/libs/icu/i18n/rbt.cpp
index 4cef242e58..8166b49b7d 100644
--- a/contrib/libs/icu/i18n/rbt.cpp
+++ b/contrib/libs/icu/i18n/rbt.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -191,8 +191,8 @@ RuleBasedTransliterator::~RuleBasedTransliterator() {
}
}
-RuleBasedTransliterator*
-RuleBasedTransliterator::clone() const {
+RuleBasedTransliterator*
+RuleBasedTransliterator::clone() const {
return new RuleBasedTransliterator(*this);
}
@@ -252,8 +252,8 @@ RuleBasedTransliterator::handleTransliterate(Replaceable& text, UTransPosition&
// Shared RBT data protected by transliteratorDataMutex.
//
// TODO(andy): Need a better scheme for handling this.
-
- static UMutex transliteratorDataMutex;
+
+ static UMutex transliteratorDataMutex;
UBool needToLock;
{
Mutex m;
diff --git a/contrib/libs/icu/i18n/rbt.h b/contrib/libs/icu/i18n/rbt.h
index 97ef01e140..b7ae39615a 100644
--- a/contrib/libs/icu/i18n/rbt.h
+++ b/contrib/libs/icu/i18n/rbt.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -29,10 +29,10 @@ class TransliterationRuleData;
/**
* <code>RuleBasedTransliterator</code> is a transliterator
- * built from a set of rules as defined for
- * Transliterator::createFromRules().
- * See the C++ class Transliterator documentation for the rule syntax.
- *
+ * built from a set of rules as defined for
+ * Transliterator::createFromRules().
+ * See the C++ class Transliterator documentation for the rule syntax.
+ *
* @author Alan Liu
* @internal Use transliterator factory methods instead since this class will be removed in that release.
*/
@@ -144,7 +144,7 @@ public:
* Implement Transliterator API.
* @internal Use transliterator factory methods instead since this class will be removed in that release.
*/
- virtual RuleBasedTransliterator* clone() const;
+ virtual RuleBasedTransliterator* clone() const;
protected:
/**
diff --git a/contrib/libs/icu/i18n/rbt_data.cpp b/contrib/libs/icu/i18n/rbt_data.cpp
index 4b596ac6c4..76e3104bff 100644
--- a/contrib/libs/icu/i18n/rbt_data.cpp
+++ b/contrib/libs/icu/i18n/rbt_data.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
diff --git a/contrib/libs/icu/i18n/rbt_data.h b/contrib/libs/icu/i18n/rbt_data.h
index 52a961dde0..f3a8a3f10d 100644
--- a/contrib/libs/icu/i18n/rbt_data.h
+++ b/contrib/libs/icu/i18n/rbt_data.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
diff --git a/contrib/libs/icu/i18n/rbt_pars.cpp b/contrib/libs/icu/i18n/rbt_pars.cpp
index 1ae5b81f03..b5fe0c6366 100644
--- a/contrib/libs/icu/i18n/rbt_pars.cpp
+++ b/contrib/libs/icu/i18n/rbt_pars.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -194,9 +194,9 @@ const UnicodeFunctor* ParseData::lookupMatcher(UChar32 ch) const {
const UnicodeFunctor* set = NULL;
int32_t i = ch - data->variablesBase;
if (i >= 0 && i < variablesVector->size()) {
- int32_t j = ch - data->variablesBase;
- set = (j < variablesVector->size()) ?
- (UnicodeFunctor*) variablesVector->elementAt(j) : 0;
+ int32_t j = ch - data->variablesBase;
+ set = (j < variablesVector->size()) ?
+ (UnicodeFunctor*) variablesVector->elementAt(j) : 0;
}
return set;
}
@@ -1108,17 +1108,17 @@ void TransliteratorParser::parseRules(const UnicodeString& rule,
}
data->variableNames.removeAll();
- int32_t p = UHASH_FIRST;
- const UHashElement* he = variableNames.nextElement(p);
+ int32_t p = UHASH_FIRST;
+ const UHashElement* he = variableNames.nextElement(p);
while (he != NULL) {
- UnicodeString* tempus = ((UnicodeString*)(he->value.pointer))->clone();
+ UnicodeString* tempus = ((UnicodeString*)(he->value.pointer))->clone();
if (tempus == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
data->variableNames.put(*((UnicodeString*)(he->key.pointer)),
tempus, status);
- he = variableNames.nextElement(p);
+ he = variableNames.nextElement(p);
}
}
variablesVector.removeAllElements(); // keeps them from getting deleted when we succeed
diff --git a/contrib/libs/icu/i18n/rbt_pars.h b/contrib/libs/icu/i18n/rbt_pars.h
index 61ce9727e0..cf002eb27c 100644
--- a/contrib/libs/icu/i18n/rbt_pars.h
+++ b/contrib/libs/icu/i18n/rbt_pars.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
diff --git a/contrib/libs/icu/i18n/rbt_rule.cpp b/contrib/libs/icu/i18n/rbt_rule.cpp
index 6cc5325c46..26f7415ce2 100644
--- a/contrib/libs/icu/i18n/rbt_rule.cpp
+++ b/contrib/libs/icu/i18n/rbt_rule.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -180,13 +180,13 @@ TransliterationRule::TransliterationRule(TransliterationRule& other) :
}
if (other.anteContext != NULL) {
- anteContext = other.anteContext->clone();
+ anteContext = other.anteContext->clone();
}
if (other.key != NULL) {
- key = other.key->clone();
+ key = other.key->clone();
}
if (other.postContext != NULL) {
- postContext = other.postContext->clone();
+ postContext = other.postContext->clone();
}
output = other.output->clone();
}
diff --git a/contrib/libs/icu/i18n/rbt_rule.h b/contrib/libs/icu/i18n/rbt_rule.h
index 5501981266..2244704969 100644
--- a/contrib/libs/icu/i18n/rbt_rule.h
+++ b/contrib/libs/icu/i18n/rbt_rule.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
* Copyright (C) {1999-2001}, International Business Machines Corporation and others. All Rights Reserved.
diff --git a/contrib/libs/icu/i18n/rbt_set.cpp b/contrib/libs/icu/i18n/rbt_set.cpp
index d8d0384dda..81297d32b2 100644
--- a/contrib/libs/icu/i18n/rbt_set.cpp
+++ b/contrib/libs/icu/i18n/rbt_set.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
diff --git a/contrib/libs/icu/i18n/rbt_set.h b/contrib/libs/icu/i18n/rbt_set.h
index b4b46786bf..c38276594b 100644
--- a/contrib/libs/icu/i18n/rbt_set.h
+++ b/contrib/libs/icu/i18n/rbt_set.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
diff --git a/contrib/libs/icu/i18n/rbtz.cpp b/contrib/libs/icu/i18n/rbtz.cpp
index 3249a32a1c..af86c8375a 100644
--- a/contrib/libs/icu/i18n/rbtz.cpp
+++ b/contrib/libs/icu/i18n/rbtz.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -149,7 +149,7 @@ RuleBasedTimeZone::addTransitionRule(TimeZoneRule* rule, UErrorCode& status) {
void
RuleBasedTimeZone::completeConst(UErrorCode& status) const {
- static UMutex gLock;
+ static UMutex gLock;
if (U_FAILURE(status)) {
return;
}
@@ -356,8 +356,8 @@ cleanup:
fUpToDate = FALSE;
}
-RuleBasedTimeZone*
-RuleBasedTimeZone::clone() const {
+RuleBasedTimeZone*
+RuleBasedTimeZone::clone() const {
return new RuleBasedTimeZone(*this);
}
diff --git a/contrib/libs/icu/i18n/regexcmp.cpp b/contrib/libs/icu/i18n/regexcmp.cpp
index dd777b7538..99169dcd60 100644
--- a/contrib/libs/icu/i18n/regexcmp.cpp
+++ b/contrib/libs/icu/i18n/regexcmp.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
//
// file: regexcmp.cpp
@@ -28,7 +28,7 @@
#include "patternprops.h"
#include "putilimp.h"
#include "cmemory.h"
-#include "cstr.h"
+#include "cstr.h"
#include "cstring.h"
#include "uvectr32.h"
#include "uvectr64.h"
@@ -487,12 +487,12 @@ UBool RegexCompile::doParseActions(int32_t action)
// If this is a named capture group, add the name->group number mapping.
if (fCaptureName != NULL) {
- if (!fRXPat->initNamedCaptureMap()) {
- if (U_SUCCESS(*fStatus)) {
- error(fRXPat->fDeferredStatus);
- }
- break;
- }
+ if (!fRXPat->initNamedCaptureMap()) {
+ if (U_SUCCESS(*fStatus)) {
+ error(fRXPat->fDeferredStatus);
+ }
+ break;
+ }
int32_t groupNumber = fRXPat->fGroupMap->size();
int32_t previousMapping = uhash_puti(fRXPat->fNamedCaptureMap, fCaptureName, groupNumber, fStatus);
fCaptureName = NULL; // hash table takes ownership of the name (key) string.
@@ -564,7 +564,7 @@ UBool RegexCompile::doParseActions(int32_t action)
// sequence; don't change without making updates there too.
//
// Compiles to
- // 1 LA_START dataLoc Saves SP, Input Pos, Active input region.
+ // 1 LA_START dataLoc Saves SP, Input Pos, Active input region.
// 2. STATE_SAVE 4 on failure of lookahead, goto 4
// 3 JMP 6 continue ...
//
@@ -578,14 +578,14 @@ UBool RegexCompile::doParseActions(int32_t action)
// 8. code for parenthesized stuff.
// 9. LA_END
//
- // Four data slots are reserved, for saving state on entry to the look-around
- // 0: stack pointer on entry.
- // 1: input position on entry.
- // 2: fActiveStart, the active bounds start on entry.
- // 3: fActiveLimit, the active bounds limit on entry.
+ // Four data slots are reserved, for saving state on entry to the look-around
+ // 0: stack pointer on entry.
+ // 1: input position on entry.
+ // 2: fActiveStart, the active bounds start on entry.
+ // 3: fActiveLimit, the active bounds limit on entry.
{
fixLiterals();
- int32_t dataLoc = allocateData(4);
+ int32_t dataLoc = allocateData(4);
appendOp(URX_LA_START, dataLoc);
appendOp(URX_STATE_SAVE, fRXPat->fCompiledPat->size()+ 2);
appendOp(URX_JMP, fRXPat->fCompiledPat->size()+ 3);
@@ -606,23 +606,23 @@ UBool RegexCompile::doParseActions(int32_t action)
case doOpenLookAheadNeg:
// Negated Lookahead. (?! stuff )
// Compiles to
- // 1. LA_START dataloc
+ // 1. LA_START dataloc
// 2. SAVE_STATE 7 // Fail within look-ahead block restores to this state,
// // which continues with the match.
// 3. NOP // Std. Open Paren sequence, for possible '|'
// 4. code for parenthesized stuff.
- // 5. LA_END // Cut back stack, remove saved state from step 2.
+ // 5. LA_END // Cut back stack, remove saved state from step 2.
// 6. BACKTRACK // code in block succeeded, so neg. lookahead fails.
// 7. END_LA // Restore match region, in case look-ahead was using
// an alternate (transparent) region.
- // Four data slots are reserved, for saving state on entry to the look-around
- // 0: stack pointer on entry.
- // 1: input position on entry.
- // 2: fActiveStart, the active bounds start on entry.
- // 3: fActiveLimit, the active bounds limit on entry.
+ // Four data slots are reserved, for saving state on entry to the look-around
+ // 0: stack pointer on entry.
+ // 1: input position on entry.
+ // 2: fActiveStart, the active bounds start on entry.
+ // 3: fActiveLimit, the active bounds limit on entry.
{
fixLiterals();
- int32_t dataLoc = allocateData(4);
+ int32_t dataLoc = allocateData(4);
appendOp(URX_LA_START, dataLoc);
appendOp(URX_STATE_SAVE, 0); // dest address will be patched later.
appendOp(URX_NOP, 0);
@@ -656,16 +656,16 @@ UBool RegexCompile::doParseActions(int32_t action)
// Allocate a block of matcher data, to contain (when running a match)
// 0: Stack ptr on entry
// 1: Input Index on entry
- // 2: fActiveStart, the active bounds start on entry.
- // 3: fActiveLimit, the active bounds limit on entry.
- // 4: Start index of match current match attempt.
- // The first four items must match the layout of data for LA_START / LA_END
+ // 2: fActiveStart, the active bounds start on entry.
+ // 3: fActiveLimit, the active bounds limit on entry.
+ // 4: Start index of match current match attempt.
+ // The first four items must match the layout of data for LA_START / LA_END
// Generate match code for any pending literals.
fixLiterals();
// Allocate data space
- int32_t dataLoc = allocateData(5);
+ int32_t dataLoc = allocateData(5);
// Emit URX_LB_START
appendOp(URX_LB_START, dataLoc);
@@ -710,16 +710,16 @@ UBool RegexCompile::doParseActions(int32_t action)
// Allocate a block of matcher data, to contain (when running a match)
// 0: Stack ptr on entry
// 1: Input Index on entry
- // 2: fActiveStart, the active bounds start on entry.
- // 3: fActiveLimit, the active bounds limit on entry.
- // 4: Start index of match current match attempt.
- // The first four items must match the layout of data for LA_START / LA_END
+ // 2: fActiveStart, the active bounds start on entry.
+ // 3: fActiveLimit, the active bounds limit on entry.
+ // 4: Start index of match current match attempt.
+ // The first four items must match the layout of data for LA_START / LA_END
// Generate match code for any pending literals.
fixLiterals();
// Allocate data space
- int32_t dataLoc = allocateData(5);
+ int32_t dataLoc = allocateData(5);
// Emit URX_LB_START
appendOp(URX_LB_START, dataLoc);
@@ -1254,10 +1254,10 @@ UBool RegexCompile::doParseActions(int32_t action)
break;
case doBackslashX:
- #if UCONFIG_NO_BREAK_ITERATION==1
- // Grapheme Cluster Boundary requires ICU break iteration.
- error(U_UNSUPPORTED_ERROR);
- #endif
+ #if UCONFIG_NO_BREAK_ITERATION==1
+ // Grapheme Cluster Boundary requires ICU break iteration.
+ error(U_UNSUPPORTED_ERROR);
+ #endif
fixLiterals(FALSE);
appendOp(URX_BACKSLASH_X, 0);
break;
@@ -1351,8 +1351,8 @@ UBool RegexCompile::doParseActions(int32_t action)
case doCompleteNamedBackRef:
{
- int32_t groupNumber =
- fRXPat->fNamedCaptureMap ? uhash_geti(fRXPat->fNamedCaptureMap, fCaptureName) : 0;
+ int32_t groupNumber =
+ fRXPat->fNamedCaptureMap ? uhash_geti(fRXPat->fNamedCaptureMap, fCaptureName) : 0;
if (groupNumber == 0) {
// Group name has not been defined.
// Could be a forward reference. If we choose to support them at some
@@ -1485,7 +1485,7 @@ UBool RegexCompile::doParseActions(int32_t action)
case 0x78: /* 'x' */ bit = UREGEX_COMMENTS; break;
case 0x2d: /* '-' */ fSetModeFlag = FALSE; break;
default:
- UPRV_UNREACHABLE; // Should never happen. Other chars are filtered out
+ UPRV_UNREACHABLE; // Should never happen. Other chars are filtered out
// by the scanner.
}
if (fSetModeFlag) {
@@ -1565,15 +1565,15 @@ UBool RegexCompile::doParseActions(int32_t action)
case doSetBackslash_s:
{
UnicodeSet *set = (UnicodeSet *)fSetStack.peek();
- set->addAll(RegexStaticSets::gStaticSets->fPropSets[URX_ISSPACE_SET]);
+ set->addAll(RegexStaticSets::gStaticSets->fPropSets[URX_ISSPACE_SET]);
break;
}
case doSetBackslash_S:
{
UnicodeSet *set = (UnicodeSet *)fSetStack.peek();
- UnicodeSet SSet;
- SSet.addAll(RegexStaticSets::gStaticSets->fPropSets[URX_ISSPACE_SET]).complement();
+ UnicodeSet SSet;
+ SSet.addAll(RegexStaticSets::gStaticSets->fPropSets[URX_ISSPACE_SET]).complement();
set->addAll(SSet);
break;
}
@@ -1642,15 +1642,15 @@ UBool RegexCompile::doParseActions(int32_t action)
case doSetBackslash_w:
{
UnicodeSet *set = (UnicodeSet *)fSetStack.peek();
- set->addAll(RegexStaticSets::gStaticSets->fPropSets[URX_ISWORD_SET]);
+ set->addAll(RegexStaticSets::gStaticSets->fPropSets[URX_ISWORD_SET]);
break;
}
case doSetBackslash_W:
{
UnicodeSet *set = (UnicodeSet *)fSetStack.peek();
- UnicodeSet SSet;
- SSet.addAll(RegexStaticSets::gStaticSets->fPropSets[URX_ISWORD_SET]).complement();
+ UnicodeSet SSet;
+ SSet.addAll(RegexStaticSets::gStaticSets->fPropSets[URX_ISWORD_SET]).complement();
set->addAll(SSet);
break;
}
@@ -1860,7 +1860,7 @@ UBool RegexCompile::doParseActions(int32_t action)
}
default:
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
if (U_FAILURE(*fStatus)) {
@@ -1967,17 +1967,17 @@ int32_t RegexCompile::buildOp(int32_t type, int32_t val) {
return 0;
}
if (type < 0 || type > 255) {
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
if (val > 0x00ffffff) {
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
if (val < 0) {
if (!(type == URX_RESERVED_OP_N || type == URX_RESERVED_OP)) {
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
if (URX_TYPE(val) != 0xff) {
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
type = URX_RESERVED_OP_N;
}
@@ -2305,13 +2305,13 @@ void RegexCompile::handleCloseParen() {
error(U_REGEX_LOOK_BEHIND_LIMIT);
break;
}
- if (minML == INT32_MAX) {
- // This condition happens when no match is possible, such as with a
- // [set] expression containing no elements.
- // In principle, the generated code to evaluate the expression could be deleted,
- // but it's probably not worth the complication.
- minML = 0;
- }
+ if (minML == INT32_MAX) {
+ // This condition happens when no match is possible, such as with a
+ // [set] expression containing no elements.
+ // In principle, the generated code to evaluate the expression could be deleted,
+ // but it's probably not worth the complication.
+ minML = 0;
+ }
U_ASSERT(minML <= maxML);
// Insert the min and max match len bounds into the URX_LB_CONT op that
@@ -2348,14 +2348,14 @@ void RegexCompile::handleCloseParen() {
error(U_REGEX_LOOK_BEHIND_LIMIT);
break;
}
- if (minML == INT32_MAX) {
- // This condition happens when no match is possible, such as with a
- // [set] expression containing no elements.
- // In principle, the generated code to evaluate the expression could be deleted,
- // but it's probably not worth the complication.
- minML = 0;
- }
-
+ if (minML == INT32_MAX) {
+ // This condition happens when no match is possible, such as with a
+ // [set] expression containing no elements.
+ // In principle, the generated code to evaluate the expression could be deleted,
+ // but it's probably not worth the complication.
+ minML = 0;
+ }
+
U_ASSERT(minML <= maxML);
// Insert the min and max match len bounds into the URX_LB_CONT op that
@@ -2373,7 +2373,7 @@ void RegexCompile::handleCloseParen() {
default:
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
// remember the next location in the compiled pattern.
@@ -2425,7 +2425,7 @@ void RegexCompile::compileSet(UnicodeSet *theSet)
{
// The set contains two or more chars. (the normal case)
// Put it into the compiled pattern as a set.
- theSet->freeze();
+ theSet->freeze();
int32_t setNumber = fRXPat->fSets->size();
fRXPat->fSets->addElement(theSet, *fStatus);
appendOp(URX_SETREF, setNumber);
@@ -2634,7 +2634,7 @@ void RegexCompile::findCaseInsensitiveStarters(UChar32 c, UnicodeSet *starterCh
if (c < UCHAR_MIN_VALUE || c > UCHAR_MAX_VALUE) {
// This function should never be called with an invalid input character.
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
} else if (u_hasBinaryProperty(c, UCHAR_CASE_SENSITIVE)) {
UChar32 caseFoldedC = u_foldCase(c, U_FOLD_CASE_DEFAULT);
starterChars->set(caseFoldedC, caseFoldedC);
@@ -2663,18 +2663,18 @@ void RegexCompile::findCaseInsensitiveStarters(UChar32 c, UnicodeSet *starterCh
}
-// Increment with overflow check.
-// val and delta will both be positive.
-
-static int32_t safeIncrement(int32_t val, int32_t delta) {
- if (INT32_MAX - val > delta) {
- return val + delta;
- } else {
- return INT32_MAX;
- }
-}
+// Increment with overflow check.
+// val and delta will both be positive.
+static int32_t safeIncrement(int32_t val, int32_t delta) {
+ if (INT32_MAX - val > delta) {
+ return val + delta;
+ } else {
+ return INT32_MAX;
+ }
+}
+
//------------------------------------------------------------------------------
//
// matchStartType Determine how a match can start.
@@ -2773,7 +2773,7 @@ void RegexCompile::matchStartType() {
fRXPat->fInitialChars->add(URX_VAL(op));
numInitialStrings += 2;
}
- currentLen = safeIncrement(currentLen, 1);
+ currentLen = safeIncrement(currentLen, 1);
atStart = FALSE;
break;
@@ -2786,7 +2786,7 @@ void RegexCompile::matchStartType() {
fRXPat->fInitialChars->addAll(*s);
numInitialStrings += 2;
}
- currentLen = safeIncrement(currentLen, 1);
+ currentLen = safeIncrement(currentLen, 1);
atStart = FALSE;
break;
@@ -2819,11 +2819,11 @@ void RegexCompile::matchStartType() {
if (currentLen == 0) {
int32_t sn = URX_VAL(op);
U_ASSERT(sn>0 && sn<URX_LAST_SET);
- const UnicodeSet &s = RegexStaticSets::gStaticSets->fPropSets[sn];
- fRXPat->fInitialChars->addAll(s);
+ const UnicodeSet &s = RegexStaticSets::gStaticSets->fPropSets[sn];
+ fRXPat->fInitialChars->addAll(s);
numInitialStrings += 2;
}
- currentLen = safeIncrement(currentLen, 1);
+ currentLen = safeIncrement(currentLen, 1);
atStart = FALSE;
break;
@@ -2832,12 +2832,12 @@ void RegexCompile::matchStartType() {
case URX_STAT_SETREF_N:
if (currentLen == 0) {
int32_t sn = URX_VAL(op);
- UnicodeSet sc;
- sc.addAll(RegexStaticSets::gStaticSets->fPropSets[sn]).complement();
+ UnicodeSet sc;
+ sc.addAll(RegexStaticSets::gStaticSets->fPropSets[sn]).complement();
fRXPat->fInitialChars->addAll(sc);
numInitialStrings += 2;
}
- currentLen = safeIncrement(currentLen, 1);
+ currentLen = safeIncrement(currentLen, 1);
atStart = FALSE;
break;
@@ -2854,7 +2854,7 @@ void RegexCompile::matchStartType() {
fRXPat->fInitialChars->addAll(s);
numInitialStrings += 2;
}
- currentLen = safeIncrement(currentLen, 1);
+ currentLen = safeIncrement(currentLen, 1);
atStart = FALSE;
break;
@@ -2871,7 +2871,7 @@ void RegexCompile::matchStartType() {
fRXPat->fInitialChars->addAll(s);
numInitialStrings += 2;
}
- currentLen = safeIncrement(currentLen, 1);
+ currentLen = safeIncrement(currentLen, 1);
atStart = FALSE;
break;
@@ -2890,7 +2890,7 @@ void RegexCompile::matchStartType() {
fRXPat->fInitialChars->addAll(s);
numInitialStrings += 2;
}
- currentLen = safeIncrement(currentLen, 1);
+ currentLen = safeIncrement(currentLen, 1);
atStart = FALSE;
break;
@@ -2914,7 +2914,7 @@ void RegexCompile::matchStartType() {
}
numInitialStrings += 2;
}
- currentLen = safeIncrement(currentLen, 1);
+ currentLen = safeIncrement(currentLen, 1);
atStart = FALSE;
break;
@@ -2930,7 +2930,7 @@ void RegexCompile::matchStartType() {
fRXPat->fInitialChars->complement();
numInitialStrings += 2;
}
- currentLen = safeIncrement(currentLen, 1);
+ currentLen = safeIncrement(currentLen, 1);
atStart = FALSE;
break;
@@ -3010,7 +3010,7 @@ void RegexCompile::matchStartType() {
fRXPat->fInitialStringLen = stringLen;
}
- currentLen = safeIncrement(currentLen, stringLen);
+ currentLen = safeIncrement(currentLen, stringLen);
atStart = FALSE;
}
break;
@@ -3035,7 +3035,7 @@ void RegexCompile::matchStartType() {
fRXPat->fInitialChars->addAll(s);
numInitialStrings += 2; // Matching on an initial string not possible.
}
- currentLen = safeIncrement(currentLen, stringLen);
+ currentLen = safeIncrement(currentLen, stringLen);
atStart = FALSE;
}
break;
@@ -3127,10 +3127,10 @@ void RegexCompile::matchStartType() {
case URX_LB_END:
case URX_LBN_CONT:
case URX_LBN_END:
- UPRV_UNREACHABLE; // Shouldn't get here. These ops should be
+ UPRV_UNREACHABLE; // Shouldn't get here. These ops should be
// consumed by the scan in URX_LA_START and LB_START
default:
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
}
@@ -3290,7 +3290,7 @@ int32_t RegexCompile::minMatchLength(int32_t start, int32_t end) {
case URX_DOTANY_ALL: // . matches one or two.
case URX_DOTANY:
case URX_DOTANY_UNIX:
- currentLen = safeIncrement(currentLen, 1);
+ currentLen = safeIncrement(currentLen, 1);
break;
@@ -3342,7 +3342,7 @@ int32_t RegexCompile::minMatchLength(int32_t start, int32_t end) {
{
loc++;
int32_t stringLenOp = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
- currentLen = safeIncrement(currentLen, URX_VAL(stringLenOp));
+ currentLen = safeIncrement(currentLen, URX_VAL(stringLenOp));
}
break;
@@ -3355,7 +3355,7 @@ int32_t RegexCompile::minMatchLength(int32_t start, int32_t end) {
// Assume a min length of one for now. A min length of zero causes
// optimization failures for a pattern like "string"+
// currentLen += URX_VAL(stringLenOp);
- currentLen = safeIncrement(currentLen, 1);
+ currentLen = safeIncrement(currentLen, 1);
}
break;
@@ -3401,7 +3401,7 @@ int32_t RegexCompile::minMatchLength(int32_t start, int32_t end) {
// it assumes that the look-ahead match might be zero-length.
// TODO: Positive lookahead could recursively do the block, then continue
// with the longer of the block or the value coming in. Ticket 6060
- int32_t depth = (opType == URX_LA_START? 2: 1);
+ int32_t depth = (opType == URX_LA_START? 2: 1);
for (;;) {
loc++;
op = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
@@ -3450,7 +3450,7 @@ int32_t RegexCompile::minMatchLength(int32_t start, int32_t end) {
break;
default:
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
}
@@ -3691,9 +3691,9 @@ int32_t RegexCompile::maxMatchLength(int32_t start, int32_t end) {
case URX_CTR_LOOP:
case URX_CTR_LOOP_NG:
- // These opcodes will be skipped over by code for URX_CTR_INIT.
+ // These opcodes will be skipped over by code for URX_CTR_INIT.
// We shouldn't encounter them here.
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
case URX_LOOP_SR_I:
case URX_LOOP_DOT_I:
@@ -3713,26 +3713,26 @@ int32_t RegexCompile::maxMatchLength(int32_t start, int32_t end) {
// End of look-ahead ops should always be consumed by the processing at
// the URX_LA_START op.
- // UPRV_UNREACHABLE;
+ // UPRV_UNREACHABLE;
case URX_LB_START:
{
// Look-behind. Scan forward until the matching look-around end,
// without processing the look-behind block.
- int32_t dataLoc = URX_VAL(op);
- for (loc = loc + 1; loc < end; ++loc) {
+ int32_t dataLoc = URX_VAL(op);
+ for (loc = loc + 1; loc < end; ++loc) {
op = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
- int32_t opType = URX_TYPE(op);
- if ((opType == URX_LA_END || opType == URX_LBN_END) && (URX_VAL(op) == dataLoc)) {
- break;
+ int32_t opType = URX_TYPE(op);
+ if ((opType == URX_LA_END || opType == URX_LBN_END) && (URX_VAL(op) == dataLoc)) {
+ break;
}
}
- U_ASSERT(loc < end);
+ U_ASSERT(loc < end);
}
break;
default:
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
@@ -3887,7 +3887,7 @@ void RegexCompile::stripNOPs() {
default:
// Some op is unaccounted for.
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
}
@@ -3904,7 +3904,7 @@ void RegexCompile::stripNOPs() {
//
//------------------------------------------------------------------------------
void RegexCompile::error(UErrorCode e) {
- if (U_SUCCESS(*fStatus) || e == U_MEMORY_ALLOCATION_ERROR) {
+ if (U_SUCCESS(*fStatus) || e == U_MEMORY_ALLOCATION_ERROR) {
*fStatus = e;
// Hmm. fParseErr (UParseError) line & offset fields are int32_t in public
// API (see common/unicode/parseerr.h), while fLineNum and fCharNum are
@@ -4023,7 +4023,7 @@ UChar32 RegexCompile::peekCharLL() {
//
//------------------------------------------------------------------------------
void RegexCompile::nextChar(RegexPatternChar &c) {
- tailRecursion:
+ tailRecursion:
fScanIndex = UTEXT_GETNATIVEINDEX(fRXPat->fPattern);
c.fChar = nextCharLL();
c.fQuoted = FALSE;
@@ -4034,9 +4034,9 @@ void RegexCompile::nextChar(RegexPatternChar &c) {
c.fChar == (UChar32)-1) {
fQuoteMode = FALSE; // Exit quote mode,
nextCharLL(); // discard the E
- // nextChar(c); // recurse to get the real next char
- goto tailRecursion; // Note: fuzz testing produced testcases that
- // resulted in stack overflow here.
+ // nextChar(c); // recurse to get the real next char
+ goto tailRecursion; // Note: fuzz testing produced testcases that
+ // resulted in stack overflow here.
}
}
else if (fInBackslashQuote) {
@@ -4154,10 +4154,10 @@ void RegexCompile::nextChar(RegexPatternChar &c) {
else if (peekCharLL() == chQ) {
// "\Q" enter quote mode, which will continue until "\E"
fQuoteMode = TRUE;
- nextCharLL(); // discard the 'Q'.
- // nextChar(c); // recurse to get the real next char.
- goto tailRecursion; // Note: fuzz testing produced test cases that
- // resulted in stack overflow here.
+ nextCharLL(); // discard the 'Q'.
+ // nextChar(c); // recurse to get the real next char.
+ goto tailRecursion; // Note: fuzz testing produced test cases that
+ // resulted in stack overflow here.
}
else
{
@@ -4389,203 +4389,203 @@ static inline void addIdentifierIgnorable(UnicodeSet *set, UErrorCode& ec) {
UnicodeSet *RegexCompile::createSetForProperty(const UnicodeString &propName, UBool negated) {
if (U_FAILURE(*fStatus)) {
- return nullptr;
+ return nullptr;
}
- LocalPointer<UnicodeSet> set;
- UErrorCode status = U_ZERO_ERROR;
-
- do { // non-loop, exists to allow breaks from the block.
- //
- // First try the property as we received it
- //
- UnicodeString setExpr;
- uint32_t usetFlags = 0;
- setExpr.append(u"[\\p{", -1);
- setExpr.append(propName);
- setExpr.append(u"}]", -1);
- if (fModeFlags & UREGEX_CASE_INSENSITIVE) {
- usetFlags |= USET_CASE_INSENSITIVE;
+ LocalPointer<UnicodeSet> set;
+ UErrorCode status = U_ZERO_ERROR;
+
+ do { // non-loop, exists to allow breaks from the block.
+ //
+ // First try the property as we received it
+ //
+ UnicodeString setExpr;
+ uint32_t usetFlags = 0;
+ setExpr.append(u"[\\p{", -1);
+ setExpr.append(propName);
+ setExpr.append(u"}]", -1);
+ if (fModeFlags & UREGEX_CASE_INSENSITIVE) {
+ usetFlags |= USET_CASE_INSENSITIVE;
+ }
+ set.adoptInsteadAndCheckErrorCode(new UnicodeSet(setExpr, usetFlags, NULL, status), status);
+ if (U_SUCCESS(status) || status == U_MEMORY_ALLOCATION_ERROR) {
+ break;
+ }
+
+ //
+ // The incoming property wasn't directly recognized by ICU.
+
+ // Check [:word:] and [:all:]. These are not recognized as a properties by ICU UnicodeSet.
+ // Java accepts 'word' with mixed case.
+ // Java accepts 'all' only in all lower case.
+
+ status = U_ZERO_ERROR;
+ if (propName.caseCompare(u"word", -1, 0) == 0) {
+ set.adoptInsteadAndCheckErrorCode(
+ RegexStaticSets::gStaticSets->fPropSets[URX_ISWORD_SET].cloneAsThawed(), status);
+ break;
}
- set.adoptInsteadAndCheckErrorCode(new UnicodeSet(setExpr, usetFlags, NULL, status), status);
- if (U_SUCCESS(status) || status == U_MEMORY_ALLOCATION_ERROR) {
- break;
+ if (propName.compare(u"all", -1) == 0) {
+ set.adoptInsteadAndCheckErrorCode(new UnicodeSet(0, 0x10ffff), status);
+ break;
}
- //
- // The incoming property wasn't directly recognized by ICU.
-
- // Check [:word:] and [:all:]. These are not recognized as a properties by ICU UnicodeSet.
- // Java accepts 'word' with mixed case.
- // Java accepts 'all' only in all lower case.
- status = U_ZERO_ERROR;
- if (propName.caseCompare(u"word", -1, 0) == 0) {
- set.adoptInsteadAndCheckErrorCode(
- RegexStaticSets::gStaticSets->fPropSets[URX_ISWORD_SET].cloneAsThawed(), status);
- break;
- }
- if (propName.compare(u"all", -1) == 0) {
- set.adoptInsteadAndCheckErrorCode(new UnicodeSet(0, 0x10ffff), status);
- break;
- }
-
-
- // Do Java InBlock expressions
+ // Do Java InBlock expressions
//
- UnicodeString mPropName = propName;
- if (mPropName.startsWith(u"In", 2) && mPropName.length() >= 3) {
- status = U_ZERO_ERROR;
- set.adoptInsteadAndCheckErrorCode(new UnicodeSet(), status);
- if (U_FAILURE(status)) {
- break;
- }
- UnicodeString blockName(mPropName, 2); // Property with the leading "In" removed.
- set->applyPropertyAlias(UnicodeString(u"Block"), blockName, status);
- break;
+ UnicodeString mPropName = propName;
+ if (mPropName.startsWith(u"In", 2) && mPropName.length() >= 3) {
+ status = U_ZERO_ERROR;
+ set.adoptInsteadAndCheckErrorCode(new UnicodeSet(), status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ UnicodeString blockName(mPropName, 2); // Property with the leading "In" removed.
+ set->applyPropertyAlias(UnicodeString(u"Block"), blockName, status);
+ break;
}
- // Check for the Java form "IsBooleanPropertyValue", which we will recast
- // as "BooleanPropertyValue". The property value can be either a
- // a General Category or a Script Name.
-
- if (propName.startsWith(u"Is", 2) && propName.length()>=3) {
- mPropName.remove(0, 2); // Strip the "Is"
- if (mPropName.indexOf(u'=') >= 0) {
- // Reject any "Is..." property expression containing an '=', that is,
- // any non-binary property expression.
- status = U_REGEX_PROPERTY_SYNTAX;
- break;
- }
-
- if (mPropName.caseCompare(u"assigned", -1, 0) == 0) {
- mPropName.setTo(u"unassigned", -1);
- negated = !negated;
- } else if (mPropName.caseCompare(u"TitleCase", -1, 0) == 0) {
- mPropName.setTo(u"Titlecase_Letter", -1);
- }
-
- mPropName.insert(0, u"[\\p{", -1);
- mPropName.append(u"}]", -1);
- set.adoptInsteadAndCheckErrorCode(new UnicodeSet(mPropName, *fStatus), status);
-
- if (U_SUCCESS(status) && !set->isEmpty() && (usetFlags & USET_CASE_INSENSITIVE)) {
+ // Check for the Java form "IsBooleanPropertyValue", which we will recast
+ // as "BooleanPropertyValue". The property value can be either a
+ // a General Category or a Script Name.
+
+ if (propName.startsWith(u"Is", 2) && propName.length()>=3) {
+ mPropName.remove(0, 2); // Strip the "Is"
+ if (mPropName.indexOf(u'=') >= 0) {
+ // Reject any "Is..." property expression containing an '=', that is,
+ // any non-binary property expression.
+ status = U_REGEX_PROPERTY_SYNTAX;
+ break;
+ }
+
+ if (mPropName.caseCompare(u"assigned", -1, 0) == 0) {
+ mPropName.setTo(u"unassigned", -1);
+ negated = !negated;
+ } else if (mPropName.caseCompare(u"TitleCase", -1, 0) == 0) {
+ mPropName.setTo(u"Titlecase_Letter", -1);
+ }
+
+ mPropName.insert(0, u"[\\p{", -1);
+ mPropName.append(u"}]", -1);
+ set.adoptInsteadAndCheckErrorCode(new UnicodeSet(mPropName, *fStatus), status);
+
+ if (U_SUCCESS(status) && !set->isEmpty() && (usetFlags & USET_CASE_INSENSITIVE)) {
set->closeOver(USET_CASE_INSENSITIVE);
}
- break;
-
- }
-
- if (propName.startsWith(u"java", -1)) {
- status = U_ZERO_ERROR;
- set.adoptInsteadAndCheckErrorCode(new UnicodeSet(), status);
- if (U_FAILURE(status)) {
- break;
- }
- //
- // Try the various Java specific properties.
- // These all begin with "java"
- //
- if (propName.compare(u"javaDefined", -1) == 0) {
- addCategory(set.getAlias(), U_GC_CN_MASK, status);
+ break;
+
+ }
+
+ if (propName.startsWith(u"java", -1)) {
+ status = U_ZERO_ERROR;
+ set.adoptInsteadAndCheckErrorCode(new UnicodeSet(), status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ //
+ // Try the various Java specific properties.
+ // These all begin with "java"
+ //
+ if (propName.compare(u"javaDefined", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_CN_MASK, status);
set->complement();
}
- else if (propName.compare(u"javaDigit", -1) == 0) {
- addCategory(set.getAlias(), U_GC_ND_MASK, status);
- }
- else if (propName.compare(u"javaIdentifierIgnorable", -1) == 0) {
- addIdentifierIgnorable(set.getAlias(), status);
- }
- else if (propName.compare(u"javaISOControl", -1) == 0) {
- set->add(0, 0x1F).add(0x7F, 0x9F);
- }
- else if (propName.compare(u"javaJavaIdentifierPart", -1) == 0) {
- addCategory(set.getAlias(), U_GC_L_MASK, status);
- addCategory(set.getAlias(), U_GC_SC_MASK, status);
- addCategory(set.getAlias(), U_GC_PC_MASK, status);
- addCategory(set.getAlias(), U_GC_ND_MASK, status);
- addCategory(set.getAlias(), U_GC_NL_MASK, status);
- addCategory(set.getAlias(), U_GC_MC_MASK, status);
- addCategory(set.getAlias(), U_GC_MN_MASK, status);
- addIdentifierIgnorable(set.getAlias(), status);
- }
- else if (propName.compare(u"javaJavaIdentifierStart", -1) == 0) {
- addCategory(set.getAlias(), U_GC_L_MASK, status);
- addCategory(set.getAlias(), U_GC_NL_MASK, status);
- addCategory(set.getAlias(), U_GC_SC_MASK, status);
- addCategory(set.getAlias(), U_GC_PC_MASK, status);
- }
- else if (propName.compare(u"javaLetter", -1) == 0) {
- addCategory(set.getAlias(), U_GC_L_MASK, status);
- }
- else if (propName.compare(u"javaLetterOrDigit", -1) == 0) {
- addCategory(set.getAlias(), U_GC_L_MASK, status);
- addCategory(set.getAlias(), U_GC_ND_MASK, status);
- }
- else if (propName.compare(u"javaLowerCase", -1) == 0) {
- addCategory(set.getAlias(), U_GC_LL_MASK, status);
- }
- else if (propName.compare(u"javaMirrored", -1) == 0) {
- set->applyIntPropertyValue(UCHAR_BIDI_MIRRORED, 1, status);
- }
- else if (propName.compare(u"javaSpaceChar", -1) == 0) {
- addCategory(set.getAlias(), U_GC_Z_MASK, status);
- }
- else if (propName.compare(u"javaSupplementaryCodePoint", -1) == 0) {
- set->add(0x10000, UnicodeSet::MAX_VALUE);
- }
- else if (propName.compare(u"javaTitleCase", -1) == 0) {
- addCategory(set.getAlias(), U_GC_LT_MASK, status);
- }
- else if (propName.compare(u"javaUnicodeIdentifierStart", -1) == 0) {
- addCategory(set.getAlias(), U_GC_L_MASK, status);
- addCategory(set.getAlias(), U_GC_NL_MASK, status);
- }
- else if (propName.compare(u"javaUnicodeIdentifierPart", -1) == 0) {
- addCategory(set.getAlias(), U_GC_L_MASK, status);
- addCategory(set.getAlias(), U_GC_PC_MASK, status);
- addCategory(set.getAlias(), U_GC_ND_MASK, status);
- addCategory(set.getAlias(), U_GC_NL_MASK, status);
- addCategory(set.getAlias(), U_GC_MC_MASK, status);
- addCategory(set.getAlias(), U_GC_MN_MASK, status);
- addIdentifierIgnorable(set.getAlias(), status);
- }
- else if (propName.compare(u"javaUpperCase", -1) == 0) {
- addCategory(set.getAlias(), U_GC_LU_MASK, status);
- }
- else if (propName.compare(u"javaValidCodePoint", -1) == 0) {
- set->add(0, UnicodeSet::MAX_VALUE);
- }
- else if (propName.compare(u"javaWhitespace", -1) == 0) {
- addCategory(set.getAlias(), U_GC_Z_MASK, status);
- set->removeAll(UnicodeSet().add(0xa0).add(0x2007).add(0x202f));
- set->add(9, 0x0d).add(0x1c, 0x1f);
- } else {
- status = U_REGEX_PROPERTY_SYNTAX;
- }
-
- if (U_SUCCESS(status) && !set->isEmpty() && (usetFlags & USET_CASE_INSENSITIVE)) {
- set->closeOver(USET_CASE_INSENSITIVE);
- }
- break;
- }
-
- // Unrecognized property. ICU didn't like it as it was, and none of the Java compatibility
- // extensions matched it.
- status = U_REGEX_PROPERTY_SYNTAX;
- } while (false); // End of do loop block. Code above breaks out of the block on success or hard failure.
-
- if (U_SUCCESS(status)) {
- U_ASSERT(set.isValid());
- if (negated) {
- set->complement();
- }
- return set.orphan();
- } else {
- if (status == U_ILLEGAL_ARGUMENT_ERROR) {
- status = U_REGEX_PROPERTY_SYNTAX;
+ else if (propName.compare(u"javaDigit", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_ND_MASK, status);
+ }
+ else if (propName.compare(u"javaIdentifierIgnorable", -1) == 0) {
+ addIdentifierIgnorable(set.getAlias(), status);
+ }
+ else if (propName.compare(u"javaISOControl", -1) == 0) {
+ set->add(0, 0x1F).add(0x7F, 0x9F);
+ }
+ else if (propName.compare(u"javaJavaIdentifierPart", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_L_MASK, status);
+ addCategory(set.getAlias(), U_GC_SC_MASK, status);
+ addCategory(set.getAlias(), U_GC_PC_MASK, status);
+ addCategory(set.getAlias(), U_GC_ND_MASK, status);
+ addCategory(set.getAlias(), U_GC_NL_MASK, status);
+ addCategory(set.getAlias(), U_GC_MC_MASK, status);
+ addCategory(set.getAlias(), U_GC_MN_MASK, status);
+ addIdentifierIgnorable(set.getAlias(), status);
+ }
+ else if (propName.compare(u"javaJavaIdentifierStart", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_L_MASK, status);
+ addCategory(set.getAlias(), U_GC_NL_MASK, status);
+ addCategory(set.getAlias(), U_GC_SC_MASK, status);
+ addCategory(set.getAlias(), U_GC_PC_MASK, status);
+ }
+ else if (propName.compare(u"javaLetter", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_L_MASK, status);
+ }
+ else if (propName.compare(u"javaLetterOrDigit", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_L_MASK, status);
+ addCategory(set.getAlias(), U_GC_ND_MASK, status);
+ }
+ else if (propName.compare(u"javaLowerCase", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_LL_MASK, status);
+ }
+ else if (propName.compare(u"javaMirrored", -1) == 0) {
+ set->applyIntPropertyValue(UCHAR_BIDI_MIRRORED, 1, status);
+ }
+ else if (propName.compare(u"javaSpaceChar", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_Z_MASK, status);
+ }
+ else if (propName.compare(u"javaSupplementaryCodePoint", -1) == 0) {
+ set->add(0x10000, UnicodeSet::MAX_VALUE);
+ }
+ else if (propName.compare(u"javaTitleCase", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_LT_MASK, status);
+ }
+ else if (propName.compare(u"javaUnicodeIdentifierStart", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_L_MASK, status);
+ addCategory(set.getAlias(), U_GC_NL_MASK, status);
+ }
+ else if (propName.compare(u"javaUnicodeIdentifierPart", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_L_MASK, status);
+ addCategory(set.getAlias(), U_GC_PC_MASK, status);
+ addCategory(set.getAlias(), U_GC_ND_MASK, status);
+ addCategory(set.getAlias(), U_GC_NL_MASK, status);
+ addCategory(set.getAlias(), U_GC_MC_MASK, status);
+ addCategory(set.getAlias(), U_GC_MN_MASK, status);
+ addIdentifierIgnorable(set.getAlias(), status);
+ }
+ else if (propName.compare(u"javaUpperCase", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_LU_MASK, status);
+ }
+ else if (propName.compare(u"javaValidCodePoint", -1) == 0) {
+ set->add(0, UnicodeSet::MAX_VALUE);
+ }
+ else if (propName.compare(u"javaWhitespace", -1) == 0) {
+ addCategory(set.getAlias(), U_GC_Z_MASK, status);
+ set->removeAll(UnicodeSet().add(0xa0).add(0x2007).add(0x202f));
+ set->add(9, 0x0d).add(0x1c, 0x1f);
+ } else {
+ status = U_REGEX_PROPERTY_SYNTAX;
+ }
+
+ if (U_SUCCESS(status) && !set->isEmpty() && (usetFlags & USET_CASE_INSENSITIVE)) {
+ set->closeOver(USET_CASE_INSENSITIVE);
+ }
+ break;
}
- error(status);
- return nullptr;
+
+ // Unrecognized property. ICU didn't like it as it was, and none of the Java compatibility
+ // extensions matched it.
+ status = U_REGEX_PROPERTY_SYNTAX;
+ } while (false); // End of do loop block. Code above breaks out of the block on success or hard failure.
+
+ if (U_SUCCESS(status)) {
+ U_ASSERT(set.isValid());
+ if (negated) {
+ set->complement();
+ }
+ return set.orphan();
+ } else {
+ if (status == U_ILLEGAL_ARGUMENT_ERROR) {
+ status = U_REGEX_PROPERTY_SYNTAX;
+ }
+ error(status);
+ return nullptr;
}
}
@@ -4638,7 +4638,7 @@ void RegexCompile::setEval(int32_t nextOp) {
delete rightOperand;
break;
default:
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
}
}
diff --git a/contrib/libs/icu/i18n/regexcmp.h b/contrib/libs/icu/i18n/regexcmp.h
index f2aeea909e..279c81a257 100644
--- a/contrib/libs/icu/i18n/regexcmp.h
+++ b/contrib/libs/icu/i18n/regexcmp.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
//
// regexcmp.h
diff --git a/contrib/libs/icu/i18n/regexcst.h b/contrib/libs/icu/i18n/regexcst.h
index d44c2aec2b..db32a4ca1c 100644
--- a/contrib/libs/icu/i18n/regexcst.h
+++ b/contrib/libs/icu/i18n/regexcst.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
//---------------------------------------------------------------------------------
//
@@ -20,117 +20,117 @@ U_NAMESPACE_BEGIN
//
// Character classes for regex pattern scanning.
//
- static const uint8_t kRuleSet_digit_char = 128;
- static const uint8_t kRuleSet_ascii_letter = 129;
+ static const uint8_t kRuleSet_digit_char = 128;
+ static const uint8_t kRuleSet_ascii_letter = 129;
static const uint8_t kRuleSet_rule_char = 130;
- constexpr uint32_t kRuleSet_count = 131-128;
+ constexpr uint32_t kRuleSet_count = 131-128;
enum Regex_PatternParseAction {
- doSetBackslash_D,
- doBackslashh,
- doBackslashH,
+ doSetBackslash_D,
+ doBackslashh,
+ doBackslashH,
doSetLiteralEscaped,
- doOpenLookAheadNeg,
- doCompleteNamedBackRef,
- doPatStart,
- doBackslashS,
- doBackslashD,
- doNGStar,
+ doOpenLookAheadNeg,
+ doCompleteNamedBackRef,
+ doPatStart,
+ doBackslashS,
+ doBackslashD,
+ doNGStar,
doNOP,
- doBackslashX,
- doSetLiteral,
- doContinueNamedCapture,
- doBackslashG,
- doBackslashR,
- doSetBegin,
- doSetBackslash_v,
- doPossessivePlus,
- doPerlInline,
+ doBackslashX,
+ doSetLiteral,
+ doContinueNamedCapture,
+ doBackslashG,
+ doBackslashR,
+ doSetBegin,
+ doSetBackslash_v,
+ doPossessivePlus,
+ doPerlInline,
doBackslashZ,
doSetAddAmp,
doSetBeginDifference1,
- doIntervalError,
+ doIntervalError,
doSetNegate,
- doIntervalInit,
- doSetIntersection2,
- doPossessiveInterval,
+ doIntervalInit,
+ doSetIntersection2,
+ doPossessiveInterval,
doRuleError,
- doBackslashW,
- doContinueNamedBackRef,
- doOpenNonCaptureParen,
- doExit,
- doSetNamedChar,
- doSetBackslash_V,
+ doBackslashW,
+ doContinueNamedBackRef,
+ doOpenNonCaptureParen,
+ doExit,
+ doSetNamedChar,
+ doSetBackslash_V,
doConditionalExpr,
- doEscapeError,
- doBadOpenParenType,
+ doEscapeError,
+ doBadOpenParenType,
doPossessiveStar,
- doSetAddDash,
- doEscapedLiteralChar,
- doSetBackslash_w,
- doIntervalUpperDigit,
- doBackslashv,
- doSetBackslash_S,
- doSetNoCloseError,
- doSetProp,
- doBackslashB,
- doSetEnd,
- doSetRange,
- doMatchModeParen,
+ doSetAddDash,
+ doEscapedLiteralChar,
+ doSetBackslash_w,
+ doIntervalUpperDigit,
+ doBackslashv,
+ doSetBackslash_S,
+ doSetNoCloseError,
+ doSetProp,
+ doBackslashB,
+ doSetEnd,
+ doSetRange,
+ doMatchModeParen,
doPlus,
- doBackslashV,
- doSetMatchMode,
- doBackslashz,
- doSetNamedRange,
- doOpenLookBehindNeg,
- doInterval,
- doBadNamedCapture,
- doBeginMatchMode,
- doBackslashd,
- doPatFinish,
- doNamedChar,
- doNGPlus,
- doSetDifference2,
- doSetBackslash_H,
+ doBackslashV,
+ doSetMatchMode,
+ doBackslashz,
+ doSetNamedRange,
+ doOpenLookBehindNeg,
+ doInterval,
+ doBadNamedCapture,
+ doBeginMatchMode,
+ doBackslashd,
+ doPatFinish,
+ doNamedChar,
+ doNGPlus,
+ doSetDifference2,
+ doSetBackslash_H,
doCloseParen,
- doDotAny,
- doOpenCaptureParen,
- doEnterQuoteMode,
- doOpenAtomicParen,
- doBadModeFlag,
- doSetBackslash_d,
- doSetFinish,
- doProperty,
- doBeginNamedBackRef,
+ doDotAny,
+ doOpenCaptureParen,
+ doEnterQuoteMode,
+ doOpenAtomicParen,
+ doBadModeFlag,
+ doSetBackslash_d,
+ doSetFinish,
+ doProperty,
+ doBeginNamedBackRef,
doBackRef,
doOpt,
- doDollar,
- doBeginNamedCapture,
- doNGInterval,
- doSetOpError,
- doSetPosixProp,
+ doDollar,
+ doBeginNamedCapture,
+ doNGInterval,
+ doSetOpError,
+ doSetPosixProp,
doSetBeginIntersection1,
- doBackslashb,
- doSetBeginUnion,
- doIntevalLowerDigit,
- doSetBackslash_h,
- doStar,
- doMatchMode,
+ doBackslashb,
+ doSetBeginUnion,
+ doIntevalLowerDigit,
+ doSetBackslash_h,
+ doStar,
+ doMatchMode,
doBackslashA,
- doOpenLookBehind,
- doPossessiveOpt,
- doOrOperator,
- doBackslashw,
- doBackslashs,
+ doOpenLookBehind,
+ doPossessiveOpt,
+ doOrOperator,
+ doBackslashw,
+ doBackslashs,
doLiteralChar,
doSuppressComments,
- doCaret,
- doIntervalSame,
- doNGOpt,
- doOpenLookAhead,
- doSetBackslash_W,
+ doCaret,
+ doIntervalSame,
+ doNGOpt,
+ doOpenLookAhead,
+ doSetBackslash_W,
doMismatchedParenErr,
- doSetBackslash_s,
+ doSetBackslash_s,
rbbiLastAction};
//-------------------------------------------------------------------------------
@@ -197,7 +197,7 @@ static const struct RegexTableEl gRuleParseStateTable[] = {
, {doBadOpenParenType, 255, 206,0, FALSE} // 45
, {doOpenLookBehind, 61 /* = */, 2, 20, TRUE} // 46 open-paren-lookbehind
, {doOpenLookBehindNeg, 33 /* ! */, 2, 20, TRUE} // 47
- , {doBeginNamedCapture, 129, 64,0, FALSE} // 48
+ , {doBeginNamedCapture, 129, 64,0, FALSE} // 48
, {doBadOpenParenType, 255, 206,0, FALSE} // 49
, {doNOP, 41 /* ) */, 255,0, TRUE} // 50 paren-comment
, {doMismatchedParenErr, 253, 206,0, FALSE} // 51
@@ -213,8 +213,8 @@ static const struct RegexTableEl gRuleParseStateTable[] = {
, {doSetMatchMode, 41 /* ) */, 2,0, TRUE} // 61
, {doMatchModeParen, 58 /* : */, 2, 14, TRUE} // 62
, {doBadModeFlag, 255, 206,0, FALSE} // 63
- , {doContinueNamedCapture, 129, 64,0, TRUE} // 64 named-capture
- , {doContinueNamedCapture, 128, 64,0, TRUE} // 65
+ , {doContinueNamedCapture, 129, 64,0, TRUE} // 64 named-capture
+ , {doContinueNamedCapture, 128, 64,0, TRUE} // 65
, {doOpenCaptureParen, 62 /* > */, 2, 14, TRUE} // 66
, {doBadNamedCapture, 255, 206,0, FALSE} // 67
, {doNGStar, 63 /* ? */, 20,0, TRUE} // 68 quant-star
@@ -226,13 +226,13 @@ static const struct RegexTableEl gRuleParseStateTable[] = {
, {doNGOpt, 63 /* ? */, 20,0, TRUE} // 74 quant-opt
, {doPossessiveOpt, 43 /* + */, 20,0, TRUE} // 75
, {doOpt, 255, 20,0, FALSE} // 76
- , {doNOP, 128, 79,0, FALSE} // 77 interval-open
+ , {doNOP, 128, 79,0, FALSE} // 77 interval-open
, {doIntervalError, 255, 206,0, FALSE} // 78
- , {doIntevalLowerDigit, 128, 79,0, TRUE} // 79 interval-lower
+ , {doIntevalLowerDigit, 128, 79,0, TRUE} // 79 interval-lower
, {doNOP, 44 /* , */, 83,0, TRUE} // 80
, {doIntervalSame, 125 /* } */, 86,0, TRUE} // 81
, {doIntervalError, 255, 206,0, FALSE} // 82
- , {doIntervalUpperDigit, 128, 83,0, TRUE} // 83 interval-upper
+ , {doIntervalUpperDigit, 128, 83,0, TRUE} // 83 interval-upper
, {doNOP, 125 /* } */, 86,0, TRUE} // 84
, {doIntervalError, 255, 206,0, FALSE} // 85
, {doNGInterval, 63 /* ? */, 20,0, TRUE} // 86 interval-type
@@ -261,15 +261,15 @@ static const struct RegexTableEl gRuleParseStateTable[] = {
, {doBackslashX, 88 /* X */, 14,0, TRUE} // 109
, {doBackslashZ, 90 /* Z */, 2,0, TRUE} // 110
, {doBackslashz, 122 /* z */, 2,0, TRUE} // 111
- , {doBackRef, 128, 14,0, TRUE} // 112
+ , {doBackRef, 128, 14,0, TRUE} // 112
, {doEscapeError, 253, 206,0, FALSE} // 113
, {doEscapedLiteralChar, 255, 14,0, TRUE} // 114
, {doBeginNamedBackRef, 60 /* < */, 117,0, TRUE} // 115 named-backref
, {doBadNamedCapture, 255, 206,0, FALSE} // 116
- , {doContinueNamedBackRef, 129, 119,0, TRUE} // 117 named-backref-2
+ , {doContinueNamedBackRef, 129, 119,0, TRUE} // 117 named-backref-2
, {doBadNamedCapture, 255, 206,0, FALSE} // 118
- , {doContinueNamedBackRef, 129, 119,0, TRUE} // 119 named-backref-3
- , {doContinueNamedBackRef, 128, 119,0, TRUE} // 120
+ , {doContinueNamedBackRef, 129, 119,0, TRUE} // 119 named-backref-3
+ , {doContinueNamedBackRef, 128, 119,0, TRUE} // 120
, {doCompleteNamedBackRef, 62 /* > */, 14,0, TRUE} // 121
, {doBadNamedCapture, 255, 206,0, FALSE} // 122
, {doSetNegate, 94 /* ^ */, 126,0, TRUE} // 123 set-open
diff --git a/contrib/libs/icu/i18n/regeximp.cpp b/contrib/libs/icu/i18n/regeximp.cpp
index d555669625..a933ae9c54 100644
--- a/contrib/libs/icu/i18n/regeximp.cpp
+++ b/contrib/libs/icu/i18n/regeximp.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
//
// Copyright (C) 2012 International Business Machines Corporation
@@ -19,7 +19,7 @@
U_NAMESPACE_BEGIN
CaseFoldingUTextIterator::CaseFoldingUTextIterator(UText &text) :
- fUText(text), fFoldChars(NULL), fFoldLength(0) {
+ fUText(text), fFoldChars(NULL), fFoldLength(0) {
}
CaseFoldingUTextIterator::~CaseFoldingUTextIterator() {}
@@ -34,7 +34,7 @@ UChar32 CaseFoldingUTextIterator::next() {
if (originalC == U_SENTINEL) {
return originalC;
}
- fFoldLength = ucase_toFullFolding(originalC, &fFoldChars, U_FOLD_CASE_DEFAULT);
+ fFoldLength = ucase_toFullFolding(originalC, &fFoldChars, U_FOLD_CASE_DEFAULT);
if (fFoldLength >= UCASE_MAX_STRING_LENGTH || fFoldLength < 0) {
// input code point folds to a single code point, possibly itself.
// See comment in ucase.h for explanation of return values from ucase_toFullFoldings.
@@ -64,7 +64,7 @@ UBool CaseFoldingUTextIterator::inExpansion() {
CaseFoldingUCharIterator::CaseFoldingUCharIterator(const UChar *chars, int64_t start, int64_t limit) :
- fChars(chars), fIndex(start), fLimit(limit), fFoldChars(NULL), fFoldLength(0) {
+ fChars(chars), fIndex(start), fLimit(limit), fFoldChars(NULL), fFoldLength(0) {
}
@@ -82,7 +82,7 @@ UChar32 CaseFoldingUCharIterator::next() {
}
U16_NEXT(fChars, fIndex, fLimit, originalC);
- fFoldLength = ucase_toFullFolding(originalC, &fFoldChars, U_FOLD_CASE_DEFAULT);
+ fFoldLength = ucase_toFullFolding(originalC, &fFoldChars, U_FOLD_CASE_DEFAULT);
if (fFoldLength >= UCASE_MAX_STRING_LENGTH || fFoldLength < 0) {
// input code point folds to a single code point, possibly itself.
// See comment in ucase.h for explanation of return values from ucase_toFullFoldings.
diff --git a/contrib/libs/icu/i18n/regeximp.h b/contrib/libs/icu/i18n/regeximp.h
index 590d216895..7376c112fb 100644
--- a/contrib/libs/icu/i18n/regeximp.h
+++ b/contrib/libs/icu/i18n/regeximp.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
//
// Copyright (C) 2002-2015 International Business Machines Corporation
@@ -123,7 +123,7 @@ enum {
// saved input position, FAIL rather than taking
// the JMP
URX_LA_START = 37, // Starting a LookAround expression.
- // Save InputPos, SP and active region in static data.
+ // Save InputPos, SP and active region in static data.
// Operand: Static data offset for the save
URX_LA_END = 38, // Ending a Lookaround expression.
// Restore InputPos and Stack to saved values.
diff --git a/contrib/libs/icu/i18n/regexst.cpp b/contrib/libs/icu/i18n/regexst.cpp
index 97e417ab5a..d117a80e9b 100644
--- a/contrib/libs/icu/i18n/regexst.cpp
+++ b/contrib/libs/icu/i18n/regexst.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
//
// regexst.h
@@ -37,99 +37,99 @@
U_NAMESPACE_BEGIN
-// "Rule Char" Characters are those with special meaning, and therefore
-// need to be escaped to appear as literals in a regexp.
-constexpr char16_t const *gRuleSet_rule_chars = u"*?+[(){}^$|\\.";
+// "Rule Char" Characters are those with special meaning, and therefore
+// need to be escaped to appear as literals in a regexp.
+constexpr char16_t const *gRuleSet_rule_chars = u"*?+[(){}^$|\\.";
//
-// The backslash escape characters that ICU's unescape() function will handle.
+// The backslash escape characters that ICU's unescape() function will handle.
//
-constexpr char16_t const *gUnescapeChars = u"acefnrtuUx";
+constexpr char16_t const *gUnescapeChars = u"acefnrtuUx";
//
-// Unicode Set pattern for Regular Expression \w
+// Unicode Set pattern for Regular Expression \w
//
-constexpr char16_t const *gIsWordPattern = u"[\\p{Alphabetic}\\p{M}\\p{Nd}\\p{Pc}\\u200c\\u200d]";
+constexpr char16_t const *gIsWordPattern = u"[\\p{Alphabetic}\\p{M}\\p{Nd}\\p{Pc}\\u200c\\u200d]";
//
// Unicode Set Definitions for Regular Expression \s
//
-constexpr char16_t const *gIsSpacePattern = u"[\\p{WhiteSpace}]";
+constexpr char16_t const *gIsSpacePattern = u"[\\p{WhiteSpace}]";
//
// UnicodeSets used in implementation of Grapheme Cluster detection, \X
//
-constexpr char16_t const *gGC_ControlPattern = u"[[:Zl:][:Zp:][:Cc:][:Cf:]-[:Grapheme_Extend:]]";
-constexpr char16_t const *gGC_ExtendPattern = u"[\\p{Grapheme_Extend}]";
-constexpr char16_t const *gGC_LPattern = u"[\\p{Hangul_Syllable_Type=L}]";
-constexpr char16_t const *gGC_VPattern = u"[\\p{Hangul_Syllable_Type=V}]";
-constexpr char16_t const *gGC_TPattern = u"[\\p{Hangul_Syllable_Type=T}]";
-constexpr char16_t const *gGC_LVPattern = u"[\\p{Hangul_Syllable_Type=LV}]";
-constexpr char16_t const *gGC_LVTPattern = u"[\\p{Hangul_Syllable_Type=LVT}]";
-
-
-RegexStaticSets *RegexStaticSets::gStaticSets = nullptr;
-UInitOnce gStaticSetsInitOnce = U_INITONCE_INITIALIZER;
-
-
-RegexStaticSets::RegexStaticSets(UErrorCode *status) {
- // Initialize the shared static sets to their correct values.
- fUnescapeCharSet.addAll(UnicodeString(true, gUnescapeChars, -1)).freeze();
- fPropSets[URX_ISWORD_SET].applyPattern(UnicodeString(true, gIsWordPattern, -1), *status).freeze();
- fPropSets[URX_ISSPACE_SET].applyPattern(UnicodeString(true, gIsSpacePattern, -1), *status).freeze();
- fPropSets[URX_GC_EXTEND].applyPattern(UnicodeString(TRUE, gGC_ExtendPattern, -1), *status).freeze();
- fPropSets[URX_GC_CONTROL].applyPattern(UnicodeString(TRUE, gGC_ControlPattern, -1), *status).freeze();
- fPropSets[URX_GC_L].applyPattern(UnicodeString(TRUE, gGC_LPattern, -1), *status).freeze();
- fPropSets[URX_GC_V].applyPattern(UnicodeString(TRUE, gGC_VPattern, -1), *status).freeze();
- fPropSets[URX_GC_T].applyPattern(UnicodeString(TRUE, gGC_TPattern, -1), *status).freeze();
- fPropSets[URX_GC_LV].applyPattern(UnicodeString(TRUE, gGC_LVPattern, -1), *status).freeze();
- fPropSets[URX_GC_LVT].applyPattern(UnicodeString(TRUE, gGC_LVTPattern, -1), *status).freeze();
+constexpr char16_t const *gGC_ControlPattern = u"[[:Zl:][:Zp:][:Cc:][:Cf:]-[:Grapheme_Extend:]]";
+constexpr char16_t const *gGC_ExtendPattern = u"[\\p{Grapheme_Extend}]";
+constexpr char16_t const *gGC_LPattern = u"[\\p{Hangul_Syllable_Type=L}]";
+constexpr char16_t const *gGC_VPattern = u"[\\p{Hangul_Syllable_Type=V}]";
+constexpr char16_t const *gGC_TPattern = u"[\\p{Hangul_Syllable_Type=T}]";
+constexpr char16_t const *gGC_LVPattern = u"[\\p{Hangul_Syllable_Type=LV}]";
+constexpr char16_t const *gGC_LVTPattern = u"[\\p{Hangul_Syllable_Type=LVT}]";
+
+
+RegexStaticSets *RegexStaticSets::gStaticSets = nullptr;
+UInitOnce gStaticSetsInitOnce = U_INITONCE_INITIALIZER;
+
+
+RegexStaticSets::RegexStaticSets(UErrorCode *status) {
+ // Initialize the shared static sets to their correct values.
+ fUnescapeCharSet.addAll(UnicodeString(true, gUnescapeChars, -1)).freeze();
+ fPropSets[URX_ISWORD_SET].applyPattern(UnicodeString(true, gIsWordPattern, -1), *status).freeze();
+ fPropSets[URX_ISSPACE_SET].applyPattern(UnicodeString(true, gIsSpacePattern, -1), *status).freeze();
+ fPropSets[URX_GC_EXTEND].applyPattern(UnicodeString(TRUE, gGC_ExtendPattern, -1), *status).freeze();
+ fPropSets[URX_GC_CONTROL].applyPattern(UnicodeString(TRUE, gGC_ControlPattern, -1), *status).freeze();
+ fPropSets[URX_GC_L].applyPattern(UnicodeString(TRUE, gGC_LPattern, -1), *status).freeze();
+ fPropSets[URX_GC_V].applyPattern(UnicodeString(TRUE, gGC_VPattern, -1), *status).freeze();
+ fPropSets[URX_GC_T].applyPattern(UnicodeString(TRUE, gGC_TPattern, -1), *status).freeze();
+ fPropSets[URX_GC_LV].applyPattern(UnicodeString(TRUE, gGC_LVPattern, -1), *status).freeze();
+ fPropSets[URX_GC_LVT].applyPattern(UnicodeString(TRUE, gGC_LVTPattern, -1), *status).freeze();
//
// "Normal" is the set of characters that don't need special handling
// when finding grapheme cluster boundaries.
//
- fPropSets[URX_GC_NORMAL].complement();
- fPropSets[URX_GC_NORMAL].remove(0xac00, 0xd7a4);
- fPropSets[URX_GC_NORMAL].removeAll(fPropSets[URX_GC_CONTROL]);
- fPropSets[URX_GC_NORMAL].removeAll(fPropSets[URX_GC_L]);
- fPropSets[URX_GC_NORMAL].removeAll(fPropSets[URX_GC_V]);
- fPropSets[URX_GC_NORMAL].removeAll(fPropSets[URX_GC_T]);
- fPropSets[URX_GC_NORMAL].freeze();
+ fPropSets[URX_GC_NORMAL].complement();
+ fPropSets[URX_GC_NORMAL].remove(0xac00, 0xd7a4);
+ fPropSets[URX_GC_NORMAL].removeAll(fPropSets[URX_GC_CONTROL]);
+ fPropSets[URX_GC_NORMAL].removeAll(fPropSets[URX_GC_L]);
+ fPropSets[URX_GC_NORMAL].removeAll(fPropSets[URX_GC_V]);
+ fPropSets[URX_GC_NORMAL].removeAll(fPropSets[URX_GC_T]);
+ fPropSets[URX_GC_NORMAL].freeze();
// Initialize the 8-bit fast bit sets from the parallel full
// UnicodeSets.
- //
- // TODO: 25 Oct 2019 are these fast 8-bit sets worth keeping?
- // Measured 3.5% gain on (non) matching with the pattern "x(?:\\S+)+x"
- // This runs in exponential time, making it easy to adjust the time for
- // convenient measuring.
- //
- // This 8 bit optimization dates from the early days of ICU,
- // with a less optimized UnicodeSet. At the time, the difference
- // was substantial.
-
- for (int32_t i=0; i<URX_LAST_SET; i++) {
- fPropSets8[i].init(&fPropSets[i]);
+ //
+ // TODO: 25 Oct 2019 are these fast 8-bit sets worth keeping?
+ // Measured 3.5% gain on (non) matching with the pattern "x(?:\\S+)+x"
+ // This runs in exponential time, making it easy to adjust the time for
+ // convenient measuring.
+ //
+ // This 8 bit optimization dates from the early days of ICU,
+ // with a less optimized UnicodeSet. At the time, the difference
+ // was substantial.
+
+ for (int32_t i=0; i<URX_LAST_SET; i++) {
+ fPropSets8[i].init(&fPropSets[i]);
}
// Sets used while parsing rules, but not referenced from the parse state table
- fRuleSets[kRuleSet_rule_char-128]
- .addAll(UnicodeString(gRuleSet_rule_chars)).complement().freeze();
-
- fRuleSets[kRuleSet_digit_char-128].add(u'0', u'9').freeze();
- fRuleSets[kRuleSet_ascii_letter-128].add(u'A', u'Z').add(u'a', u'z').freeze();
+ fRuleSets[kRuleSet_rule_char-128]
+ .addAll(UnicodeString(gRuleSet_rule_chars)).complement().freeze();
+
+ fRuleSets[kRuleSet_digit_char-128].add(u'0', u'9').freeze();
+ fRuleSets[kRuleSet_ascii_letter-128].add(u'A', u'Z').add(u'a', u'z').freeze();
fRuleDigitsAlias = &fRuleSets[kRuleSet_digit_char-128];
- // Finally, initialize an empty UText string for utility purposes
- fEmptyText = utext_openUChars(nullptr, nullptr, 0, status);
+ // Finally, initialize an empty UText string for utility purposes
+ fEmptyText = utext_openUChars(nullptr, nullptr, 0, status);
}
RegexStaticSets::~RegexStaticSets() {
- fRuleDigitsAlias = nullptr;
+ fRuleDigitsAlias = nullptr;
utext_close(fEmptyText);
}
@@ -144,21 +144,21 @@ RegexStaticSets::~RegexStaticSets() {
U_CDECL_BEGIN
static UBool U_CALLCONV
regex_cleanup(void) {
- delete RegexStaticSets::gStaticSets;
- RegexStaticSets::gStaticSets = nullptr;
- gStaticSetsInitOnce.reset();
- return TRUE;
+ delete RegexStaticSets::gStaticSets;
+ RegexStaticSets::gStaticSets = nullptr;
+ gStaticSetsInitOnce.reset();
+ return TRUE;
}
static void U_CALLCONV initStaticSets(UErrorCode &status) {
- U_ASSERT(RegexStaticSets::gStaticSets == nullptr);
+ U_ASSERT(RegexStaticSets::gStaticSets == nullptr);
ucln_i18n_registerCleanup(UCLN_I18N_REGEX, regex_cleanup);
RegexStaticSets::gStaticSets = new RegexStaticSets(&status);
if (U_FAILURE(status)) {
delete RegexStaticSets::gStaticSets;
- RegexStaticSets::gStaticSets = nullptr;
+ RegexStaticSets::gStaticSets = nullptr;
}
- if (RegexStaticSets::gStaticSets == nullptr && U_SUCCESS(status)) {
+ if (RegexStaticSets::gStaticSets == nullptr && U_SUCCESS(status)) {
status = U_MEMORY_ALLOCATION_ERROR;
}
}
diff --git a/contrib/libs/icu/i18n/regexst.h b/contrib/libs/icu/i18n/regexst.h
index bcb393dd3f..5d7c26be73 100644
--- a/contrib/libs/icu/i18n/regexst.h
+++ b/contrib/libs/icu/i18n/regexst.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
//
// regexst.h
@@ -25,7 +25,7 @@
#if !UCONFIG_NO_REGULAR_EXPRESSIONS
#include "regeximp.h"
-#include "regexcst.h"
+#include "regexcst.h"
U_NAMESPACE_BEGIN
@@ -41,15 +41,15 @@ public:
~RegexStaticSets();
static void initGlobals(UErrorCode *status);
- UnicodeSet fPropSets[URX_LAST_SET] {}; // The sets for common regex items, e.g. \s
- Regex8BitSet fPropSets8[URX_LAST_SET] {}; // Fast bitmap sets for latin-1 range for above.
+ UnicodeSet fPropSets[URX_LAST_SET] {}; // The sets for common regex items, e.g. \s
+ Regex8BitSet fPropSets8[URX_LAST_SET] {}; // Fast bitmap sets for latin-1 range for above.
- UnicodeSet fRuleSets[kRuleSet_count] {}; // Sets used while parsing regexp patterns.
- UnicodeSet fUnescapeCharSet {}; // Set of chars handled by unescape when
- // encountered with a \ in a pattern.
- UnicodeSet *fRuleDigitsAlias {};
- UText *fEmptyText {}; // An empty string, to be used when a matcher
- // is created with no input.
+ UnicodeSet fRuleSets[kRuleSet_count] {}; // Sets used while parsing regexp patterns.
+ UnicodeSet fUnescapeCharSet {}; // Set of chars handled by unescape when
+ // encountered with a \ in a pattern.
+ UnicodeSet *fRuleDigitsAlias {};
+ UText *fEmptyText {}; // An empty string, to be used when a matcher
+ // is created with no input.
};
diff --git a/contrib/libs/icu/i18n/regextxt.cpp b/contrib/libs/icu/i18n/regextxt.cpp
index 41bb4a944b..82bbc37afb 100644
--- a/contrib/libs/icu/i18n/regextxt.cpp
+++ b/contrib/libs/icu/i18n/regextxt.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/********************************************************************
* COPYRIGHT:
diff --git a/contrib/libs/icu/i18n/regextxt.h b/contrib/libs/icu/i18n/regextxt.h
index 9cfabbe415..d8772a9505 100644
--- a/contrib/libs/icu/i18n/regextxt.h
+++ b/contrib/libs/icu/i18n/regextxt.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/********************************************************************
* COPYRIGHT:
diff --git a/contrib/libs/icu/i18n/region.cpp b/contrib/libs/icu/i18n/region.cpp
index 76445aef32..064a816703 100644
--- a/contrib/libs/icu/i18n/region.cpp
+++ b/contrib/libs/icu/i18n/region.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -32,7 +32,7 @@
#include "umutex.h"
#include "uresimp.h"
#include "region_impl.h"
-#include "util.h"
+#include "util.h"
#if !UCONFIG_NO_FORMATTING
@@ -166,18 +166,18 @@ void U_CALLCONV Region::loadRegionData(UErrorCode &status) {
continents->addElement(continentName,status);
}
- UResourceBundle *groupingBundle = nullptr;
+ UResourceBundle *groupingBundle = nullptr;
while ( ures_hasNext(groupingContainment.getAlias()) ) {
- groupingBundle = ures_getNextResource(groupingContainment.getAlias(), groupingBundle, &status);
- if (U_FAILURE(status)) {
- break;
- }
- UnicodeString *groupingName = new UnicodeString(ures_getKey(groupingBundle), -1, US_INV);
- if (groupingName) {
- groupings->addElement(groupingName,status);
- }
+ groupingBundle = ures_getNextResource(groupingContainment.getAlias(), groupingBundle, &status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ UnicodeString *groupingName = new UnicodeString(ures_getKey(groupingBundle), -1, US_INV);
+ if (groupingName) {
+ groupings->addElement(groupingName,status);
+ }
}
- ures_close(groupingBundle);
+ ures_close(groupingBundle);
for ( int32_t i = 0 ; i < allRegions->size() ; i++ ) {
LocalPointer<Region> r(new Region(), status);
@@ -188,14 +188,14 @@ void U_CALLCONV Region::loadRegionData(UErrorCode &status) {
r->idStr = *regionName;
r->idStr.extract(0,r->idStr.length(),r->id,sizeof(r->id),US_INV);
- r->fType = URGN_TERRITORY; // Only temporary - figure out the real type later once the aliases are known.
+ r->fType = URGN_TERRITORY; // Only temporary - figure out the real type later once the aliases are known.
- int32_t pos = 0;
- int32_t result = ICU_Utility::parseAsciiInteger(r->idStr, pos);
- if (pos > 0) {
- r->code = result; // Convert string to number
+ int32_t pos = 0;
+ int32_t result = ICU_Utility::parseAsciiInteger(r->idStr, pos);
+ if (pos > 0) {
+ r->code = result; // Convert string to number
uhash_iput(newNumericCodeMap.getAlias(),r->code,(void *)(r.getAlias()),&status);
- r->fType = URGN_SUBCONTINENT;
+ r->fType = URGN_SUBCONTINENT;
} else {
r->code = -1;
}
@@ -227,17 +227,17 @@ void U_CALLCONV Region::loadRegionData(UErrorCode &status) {
aliasFromRegion->idStr.setTo(*aliasFromStr);
aliasFromRegion->idStr.extract(0,aliasFromRegion->idStr.length(),aliasFromRegion->id,sizeof(aliasFromRegion->id),US_INV);
uhash_put(newRegionIDMap.getAlias(),(void *)&(aliasFromRegion->idStr),(void *)aliasFromRegion,&status);
- int32_t pos = 0;
- int32_t result = ICU_Utility::parseAsciiInteger(aliasFromRegion->idStr, pos);
- if ( pos > 0 ) {
- aliasFromRegion->code = result; // Convert string to number
+ int32_t pos = 0;
+ int32_t result = ICU_Utility::parseAsciiInteger(aliasFromRegion->idStr, pos);
+ if ( pos > 0 ) {
+ aliasFromRegion->code = result; // Convert string to number
uhash_iput(newNumericCodeMap.getAlias(),aliasFromRegion->code,(void *)aliasFromRegion,&status);
} else {
aliasFromRegion->code = -1;
}
- aliasFromRegion->fType = URGN_DEPRECATED;
+ aliasFromRegion->fType = URGN_DEPRECATED;
} else {
- aliasFromRegion->fType = URGN_DEPRECATED;
+ aliasFromRegion->fType = URGN_DEPRECATED;
}
{
@@ -275,10 +275,10 @@ void U_CALLCONV Region::loadRegionData(UErrorCode &status) {
Region *r = (Region *)uhash_get(newRegionIDMap.getAlias(),(void *)&codeMappingID);
if ( r ) {
- int32_t pos = 0;
- int32_t result = ICU_Utility::parseAsciiInteger(codeMappingNumber, pos);
- if ( pos > 0 ) {
- r->code = result; // Convert string to number
+ int32_t pos = 0;
+ int32_t result = ICU_Utility::parseAsciiInteger(codeMappingNumber, pos);
+ if ( pos > 0 ) {
+ r->code = result; // Convert string to number
uhash_iput(newNumericCodeMap.getAlias(),r->code,(void *)r,&status);
}
LocalPointer<UnicodeString> code3(new UnicodeString(codeMapping3Letter), status);
@@ -293,26 +293,26 @@ void U_CALLCONV Region::loadRegionData(UErrorCode &status) {
UnicodeString WORLD_ID_STRING(WORLD_ID);
r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)&WORLD_ID_STRING);
if ( r ) {
- r->fType = URGN_WORLD;
+ r->fType = URGN_WORLD;
}
UnicodeString UNKNOWN_REGION_ID_STRING(UNKNOWN_REGION_ID);
r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)&UNKNOWN_REGION_ID_STRING);
if ( r ) {
- r->fType = URGN_UNKNOWN;
+ r->fType = URGN_UNKNOWN;
}
for ( int32_t i = 0 ; i < continents->size() ; i++ ) {
r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)continents->elementAt(i));
if ( r ) {
- r->fType = URGN_CONTINENT;
+ r->fType = URGN_CONTINENT;
}
}
for ( int32_t i = 0 ; i < groupings->size() ; i++ ) {
r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)groupings->elementAt(i));
if ( r ) {
- r->fType = URGN_GROUPING;
+ r->fType = URGN_GROUPING;
}
}
@@ -322,7 +322,7 @@ void U_CALLCONV Region::loadRegionData(UErrorCode &status) {
UnicodeString OUTLYING_OCEANIA_REGION_ID_STRING(OUTLYING_OCEANIA_REGION_ID);
r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)&OUTLYING_OCEANIA_REGION_ID_STRING);
if ( r ) {
- r->fType = URGN_SUBCONTINENT;
+ r->fType = URGN_SUBCONTINENT;
}
// Load territory containment info from the supplemental data.
@@ -359,7 +359,7 @@ void U_CALLCONV Region::loadRegionData(UErrorCode &status) {
// Set the parent region to be the containing region of the child.
// Regions of type GROUPING can't be set as the parent, since another region
// such as a SUBCONTINENT, CONTINENT, or WORLD must always be the parent.
- if ( parentRegion->fType != URGN_GROUPING) {
+ if ( parentRegion->fType != URGN_GROUPING) {
childRegion->containingRegion = parentRegion;
}
}
@@ -370,15 +370,15 @@ void U_CALLCONV Region::loadRegionData(UErrorCode &status) {
int32_t pos = UHASH_FIRST;
while ( const UHashElement* element = uhash_nextElement(newRegionIDMap.getAlias(),&pos)) {
Region *ar = (Region *)element->value.pointer;
- if ( availableRegions[ar->fType] == NULL ) {
+ if ( availableRegions[ar->fType] == NULL ) {
LocalPointer<UVector> newAr(new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status), status);
- availableRegions[ar->fType] = newAr.orphan();
+ availableRegions[ar->fType] = newAr.orphan();
}
LocalPointer<UnicodeString> arString(new UnicodeString(ar->idStr), status);
if( U_FAILURE(status) ) {
return; // error out
}
- availableRegions[ar->fType]->addElement((void *)arString.orphan(),status);
+ availableRegions[ar->fType]->addElement((void *)arString.orphan(),status);
}
ucln_i18n_registerCleanup(UCLN_I18N_REGION, region_cleanup);
@@ -419,7 +419,7 @@ void Region::cleanupRegionData() {
Region::Region ()
: code(-1),
- fType(URGN_UNKNOWN),
+ fType(URGN_UNKNOWN),
containingRegion(NULL),
containedRegions(NULL),
preferredValues(NULL) {
@@ -484,7 +484,7 @@ Region::getInstance(const char *region_code, UErrorCode &status) {
return NULL;
}
- if ( r->fType == URGN_DEPRECATED && r->preferredValues->size() == 1) {
+ if ( r->fType == URGN_DEPRECATED && r->preferredValues->size() == 1) {
StringEnumeration *pv = r->getPreferredValues(status);
pv->reset(status);
const UnicodeString *ustr = pv->snext(status);
@@ -512,7 +512,7 @@ Region::getInstance (int32_t code, UErrorCode &status) {
if ( !r ) { // Just in case there's an alias that's numeric, try to find it.
UnicodeString id;
- ICU_Utility::appendNumber(id, code, 10, 1);
+ ICU_Utility::appendNumber(id, code, 10, 1);
r = (Region *)uhash_get(regionAliases,&id);
}
@@ -525,7 +525,7 @@ Region::getInstance (int32_t code, UErrorCode &status) {
return NULL;
}
- if ( r->fType == URGN_DEPRECATED && r->preferredValues->size() == 1) {
+ if ( r->fType == URGN_DEPRECATED && r->preferredValues->size() == 1) {
StringEnumeration *pv = r->getPreferredValues(status);
pv->reset(status);
const UnicodeString *ustr = pv->snext(status);
@@ -576,7 +576,7 @@ Region::getContainingRegion(URegionType type) const {
return NULL;
}
- return ( containingRegion->fType == type)? containingRegion: containingRegion->getContainingRegion(type);
+ return ( containingRegion->fType == type)? containingRegion: containingRegion->getContainingRegion(type);
}
/**
@@ -614,9 +614,9 @@ Region::getContainedRegions( URegionType type, UErrorCode &status ) const {
StringEnumeration *cr = getContainedRegions(status);
for ( int32_t i = 0 ; i < cr->count(status) ; i++ ) {
- const char *regionId = cr->next(NULL,status);
- const Region *r = Region::getInstance(regionId,status);
- if ( r->getType() == type) {
+ const char *regionId = cr->next(NULL,status);
+ const Region *r = Region::getInstance(regionId,status);
+ if ( r->getType() == type) {
result->addElement((void *)&r->idStr,status);
} else {
StringEnumeration *children = r->getContainedRegions(type, status);
@@ -668,7 +668,7 @@ Region::contains(const Region &other) const {
StringEnumeration*
Region::getPreferredValues(UErrorCode &status) const {
umtx_initOnce(gRegionDataInitOnce, &loadRegionData, status); // returns immediately if U_FAILURE(status)
- if (U_FAILURE(status) || fType != URGN_DEPRECATED) {
+ if (U_FAILURE(status) || fType != URGN_DEPRECATED) {
return NULL;
}
return new RegionNameEnumeration(preferredValues,status);
@@ -693,7 +693,7 @@ Region::getNumericCode() const {
*/
URegionType
Region::getType() const {
- return fType;
+ return fType;
}
RegionNameEnumeration::RegionNameEnumeration(UVector *fNameList, UErrorCode& status) {
diff --git a/contrib/libs/icu/i18n/region_impl.h b/contrib/libs/icu/i18n/region_impl.h
index 5e5a64529a..3e8b208bf8 100644
--- a/contrib/libs/icu/i18n/region_impl.h
+++ b/contrib/libs/icu/i18n/region_impl.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/reldatefmt.cpp b/contrib/libs/icu/i18n/reldatefmt.cpp
index 8c6688c5b9..56e80640d0 100644
--- a/contrib/libs/icu/i18n/reldatefmt.cpp
+++ b/contrib/libs/icu/i18n/reldatefmt.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
@@ -14,10 +14,10 @@
#if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_BREAK_ITERATION
-#include <cmath>
-#include <functional>
+#include <cmath>
+#include <functional>
#include "unicode/dtfmtsym.h"
-#include "unicode/ucasemap.h"
+#include "unicode/ucasemap.h"
#include "unicode/ureldatefmt.h"
#include "unicode/udisplaycontext.h"
#include "unicode/unum.h"
@@ -42,12 +42,12 @@
#include "sharednumberformat.h"
#include "standardplural.h"
#include "unifiedcache.h"
-#include "util.h"
-#include "formatted_string_builder.h"
-#include "number_utypes.h"
-#include "number_modifiers.h"
-#include "formattedval_impl.h"
-#include "number_utils.h"
+#include "util.h"
+#include "formatted_string_builder.h"
+#include "number_utypes.h"
+#include "number_modifiers.h"
+#include "formattedval_impl.h"
+#include "number_utils.h"
// Copied from uscript_props.cpp
@@ -56,13 +56,13 @@ U_NAMESPACE_BEGIN
// RelativeDateTimeFormatter specific data for a single locale
class RelativeDateTimeCacheData: public SharedObject {
public:
- RelativeDateTimeCacheData() : combinedDateAndTime(nullptr) {
+ RelativeDateTimeCacheData() : combinedDateAndTime(nullptr) {
// Initialize the cache arrays
for (int32_t style = 0; style < UDAT_STYLE_COUNT; ++style) {
- for (int32_t relUnit = 0; relUnit < UDAT_REL_UNIT_COUNT; ++relUnit) {
+ for (int32_t relUnit = 0; relUnit < UDAT_REL_UNIT_COUNT; ++relUnit) {
for (int32_t pl = 0; pl < StandardPlural::COUNT; ++pl) {
- relativeUnitsFormatters[style][relUnit][0][pl] = nullptr;
- relativeUnitsFormatters[style][relUnit][1][pl] = nullptr;
+ relativeUnitsFormatters[style][relUnit][0][pl] = nullptr;
+ relativeUnitsFormatters[style][relUnit][1][pl] = nullptr;
}
}
}
@@ -79,7 +79,7 @@ public:
// e.g., Next Tuesday; Yesterday; etc. For third index, 0
// means past, e.g., 5 days ago; 1 means future, e.g., in 5 days.
SimpleFormatter *relativeUnitsFormatters[UDAT_STYLE_COUNT]
- [UDAT_REL_UNIT_COUNT][2][StandardPlural::COUNT];
+ [UDAT_REL_UNIT_COUNT][2][StandardPlural::COUNT];
const UnicodeString& getAbsoluteUnitString(int32_t fStyle,
UDateAbsoluteUnit unit,
@@ -88,10 +88,10 @@ public:
UDateRelativeUnit unit,
int32_t pastFutureIndex,
int32_t pluralUnit) const;
- const SimpleFormatter* getRelativeDateTimeUnitFormatter(int32_t fStyle,
- URelativeDateTimeUnit unit,
- int32_t pastFutureIndex,
- int32_t pluralUnit) const;
+ const SimpleFormatter* getRelativeDateTimeUnitFormatter(int32_t fStyle,
+ URelativeDateTimeUnit unit,
+ int32_t pastFutureIndex,
+ int32_t pluralUnit) const;
const UnicodeString emptyString;
@@ -116,7 +116,7 @@ private:
RelativeDateTimeCacheData::~RelativeDateTimeCacheData() {
// clear out the cache arrays
for (int32_t style = 0; style < UDAT_STYLE_COUNT; ++style) {
- for (int32_t relUnit = 0; relUnit < UDAT_REL_UNIT_COUNT; ++relUnit) {
+ for (int32_t relUnit = 0; relUnit < UDAT_REL_UNIT_COUNT; ++relUnit) {
for (int32_t pl = 0; pl < StandardPlural::COUNT; ++pl) {
delete relativeUnitsFormatters[style][relUnit][0][pl];
delete relativeUnitsFormatters[style][relUnit][1][pl];
@@ -145,43 +145,43 @@ const UnicodeString& RelativeDateTimeCacheData::getAbsoluteUnitString(
UDateRelativeUnit unit,
int32_t pastFutureIndex,
int32_t pluralUnit) const {
- URelativeDateTimeUnit rdtunit = UDAT_REL_UNIT_COUNT;
- switch (unit) {
- case UDAT_RELATIVE_YEARS: rdtunit = UDAT_REL_UNIT_YEAR; break;
- case UDAT_RELATIVE_MONTHS: rdtunit = UDAT_REL_UNIT_MONTH; break;
- case UDAT_RELATIVE_WEEKS: rdtunit = UDAT_REL_UNIT_WEEK; break;
- case UDAT_RELATIVE_DAYS: rdtunit = UDAT_REL_UNIT_DAY; break;
- case UDAT_RELATIVE_HOURS: rdtunit = UDAT_REL_UNIT_HOUR; break;
- case UDAT_RELATIVE_MINUTES: rdtunit = UDAT_REL_UNIT_MINUTE; break;
- case UDAT_RELATIVE_SECONDS: rdtunit = UDAT_REL_UNIT_SECOND; break;
- default: // a unit that the above method does not handle
- return nullptr;
- }
-
- return getRelativeDateTimeUnitFormatter(fStyle, rdtunit, pastFutureIndex, pluralUnit);
- }
-
- // Use fallback cache for SimpleFormatter relativeUnits.
- const SimpleFormatter* RelativeDateTimeCacheData::getRelativeDateTimeUnitFormatter(
- int32_t fStyle,
- URelativeDateTimeUnit unit,
- int32_t pastFutureIndex,
- int32_t pluralUnit) const {
- while (true) {
- int32_t style = fStyle;
- do {
- if (relativeUnitsFormatters[style][unit][pastFutureIndex][pluralUnit] != nullptr) {
- return relativeUnitsFormatters[style][unit][pastFutureIndex][pluralUnit];
- }
- style = fallBackCache[style];
- } while (style != -1);
-
- if (pluralUnit == StandardPlural::OTHER) {
- break;
+ URelativeDateTimeUnit rdtunit = UDAT_REL_UNIT_COUNT;
+ switch (unit) {
+ case UDAT_RELATIVE_YEARS: rdtunit = UDAT_REL_UNIT_YEAR; break;
+ case UDAT_RELATIVE_MONTHS: rdtunit = UDAT_REL_UNIT_MONTH; break;
+ case UDAT_RELATIVE_WEEKS: rdtunit = UDAT_REL_UNIT_WEEK; break;
+ case UDAT_RELATIVE_DAYS: rdtunit = UDAT_REL_UNIT_DAY; break;
+ case UDAT_RELATIVE_HOURS: rdtunit = UDAT_REL_UNIT_HOUR; break;
+ case UDAT_RELATIVE_MINUTES: rdtunit = UDAT_REL_UNIT_MINUTE; break;
+ case UDAT_RELATIVE_SECONDS: rdtunit = UDAT_REL_UNIT_SECOND; break;
+ default: // a unit that the above method does not handle
+ return nullptr;
+ }
+
+ return getRelativeDateTimeUnitFormatter(fStyle, rdtunit, pastFutureIndex, pluralUnit);
+ }
+
+ // Use fallback cache for SimpleFormatter relativeUnits.
+ const SimpleFormatter* RelativeDateTimeCacheData::getRelativeDateTimeUnitFormatter(
+ int32_t fStyle,
+ URelativeDateTimeUnit unit,
+ int32_t pastFutureIndex,
+ int32_t pluralUnit) const {
+ while (true) {
+ int32_t style = fStyle;
+ do {
+ if (relativeUnitsFormatters[style][unit][pastFutureIndex][pluralUnit] != nullptr) {
+ return relativeUnitsFormatters[style][unit][pastFutureIndex][pluralUnit];
+ }
+ style = fallBackCache[style];
+ } while (style != -1);
+
+ if (pluralUnit == StandardPlural::OTHER) {
+ break;
}
- pluralUnit = StandardPlural::OTHER;
- }
- return nullptr; // No formatter found.
+ pluralUnit = StandardPlural::OTHER;
+ }
+ return nullptr; // No formatter found.
}
static UBool getStringWithFallback(
@@ -254,35 +254,35 @@ struct RelDateTimeFmtDataSink : public ResourceSink {
// Converts the generic units to UDAT_RELATIVE version.
switch (genUnit) {
case SECOND:
- return UDAT_REL_UNIT_SECOND;
+ return UDAT_REL_UNIT_SECOND;
case MINUTE:
- return UDAT_REL_UNIT_MINUTE;
+ return UDAT_REL_UNIT_MINUTE;
case HOUR:
- return UDAT_REL_UNIT_HOUR;
+ return UDAT_REL_UNIT_HOUR;
case DAY:
- return UDAT_REL_UNIT_DAY;
+ return UDAT_REL_UNIT_DAY;
case WEEK:
- return UDAT_REL_UNIT_WEEK;
+ return UDAT_REL_UNIT_WEEK;
case MONTH:
- return UDAT_REL_UNIT_MONTH;
- case QUARTER:
- return UDAT_REL_UNIT_QUARTER;
+ return UDAT_REL_UNIT_MONTH;
+ case QUARTER:
+ return UDAT_REL_UNIT_QUARTER;
case YEAR:
- return UDAT_REL_UNIT_YEAR;
- case SUNDAY:
- return UDAT_REL_UNIT_SUNDAY;
- case MONDAY:
- return UDAT_REL_UNIT_MONDAY;
- case TUESDAY:
- return UDAT_REL_UNIT_TUESDAY;
- case WEDNESDAY:
- return UDAT_REL_UNIT_WEDNESDAY;
- case THURSDAY:
- return UDAT_REL_UNIT_THURSDAY;
- case FRIDAY:
- return UDAT_REL_UNIT_FRIDAY;
- case SATURDAY:
- return UDAT_REL_UNIT_SATURDAY;
+ return UDAT_REL_UNIT_YEAR;
+ case SUNDAY:
+ return UDAT_REL_UNIT_SUNDAY;
+ case MONDAY:
+ return UDAT_REL_UNIT_MONDAY;
+ case TUESDAY:
+ return UDAT_REL_UNIT_TUESDAY;
+ case WEDNESDAY:
+ return UDAT_REL_UNIT_WEDNESDAY;
+ case THURSDAY:
+ return UDAT_REL_UNIT_THURSDAY;
+ case FRIDAY:
+ return UDAT_REL_UNIT_FRIDAY;
+ case SATURDAY:
+ return UDAT_REL_UNIT_SATURDAY;
default:
return -1;
}
@@ -297,8 +297,8 @@ struct RelDateTimeFmtDataSink : public ResourceSink {
return UDAT_ABSOLUTE_WEEK;
case MONTH:
return UDAT_ABSOLUTE_MONTH;
- case QUARTER:
- return UDAT_ABSOLUTE_QUARTER;
+ case QUARTER:
+ return UDAT_ABSOLUTE_QUARTER;
case YEAR:
return UDAT_ABSOLUTE_YEAR;
case SUNDAY:
@@ -315,10 +315,10 @@ struct RelDateTimeFmtDataSink : public ResourceSink {
return UDAT_ABSOLUTE_FRIDAY;
case SATURDAY:
return UDAT_ABSOLUTE_SATURDAY;
- case HOUR:
- return UDAT_ABSOLUTE_HOUR;
- case MINUTE:
- return UDAT_ABSOLUTE_MINUTE;
+ case HOUR:
+ return UDAT_ABSOLUTE_HOUR;
+ case MINUTE:
+ return UDAT_ABSOLUTE_MINUTE;
default:
return -1;
}
@@ -363,7 +363,7 @@ struct RelDateTimeFmtDataSink : public ResourceSink {
// Utility functions
static UDateRelativeDateTimeFormatterStyle styleFromString(const char *s) {
- int32_t len = static_cast<int32_t>(uprv_strlen(s));
+ int32_t len = static_cast<int32_t>(uprv_strlen(s));
if (len >= 7 && uprv_strcmp(s + len - 7, "-narrow") == 0) {
return UDAT_STYLE_NARROW;
}
@@ -481,7 +481,7 @@ struct RelDateTimeFmtDataSink : public ResourceSink {
}
int32_t relUnitIndex = relUnitFromGeneric(genericUnit);
- if (relUnitIndex == UDAT_REL_UNIT_SECOND && uprv_strcmp(key, "0") == 0 &&
+ if (relUnitIndex == UDAT_REL_UNIT_SECOND && uprv_strcmp(key, "0") == 0 &&
outputData.absoluteUnits[style][UDAT_ABSOLUTE_NOW][UDAT_DIRECTION_PLAIN].isEmpty()) {
// Handle "NOW"
outputData.absoluteUnits[style][UDAT_ABSOLUTE_NOW]
@@ -514,10 +514,10 @@ struct RelDateTimeFmtDataSink : public ResourceSink {
outputData.relativeUnitsFormatters[style][relUnitIndex]
[pastFutureIndex];
// Only set if not already established.
- if (patterns[pluralIndex] == nullptr) {
+ if (patterns[pluralIndex] == nullptr) {
patterns[pluralIndex] = new SimpleFormatter(
value.getUnicodeString(errorCode), 0, 1, errorCode);
- if (patterns[pluralIndex] == nullptr) {
+ if (patterns[pluralIndex] == nullptr) {
errorCode = U_MEMORY_ALLOCATION_ERROR;
}
}
@@ -597,7 +597,7 @@ struct RelDateTimeFmtDataSink : public ResourceSink {
consumeAlias(key, value, errorCode);
} else {
style = styleFromString(key);
- int32_t unitSize = static_cast<int32_t>(uprv_strlen(key)) - styleSuffixLength(style);
+ int32_t unitSize = static_cast<int32_t>(uprv_strlen(key)) - styleSuffixLength(style);
genericUnit = unitOrNegativeFromString(key, unitSize);
if (style >= 0 && genericUnit != INVALID_UNIT) {
consumeTimeUnit(key, value, errorCode);
@@ -612,7 +612,7 @@ struct RelDateTimeFmtDataSink : public ResourceSink {
RelDateTimeFmtDataSink::~RelDateTimeFmtDataSink() {}
} // namespace
-static const DateFormatSymbols::DtWidthType styleToDateFormatSymbolWidth[UDAT_STYLE_COUNT] = {
+static const DateFormatSymbols::DtWidthType styleToDateFormatSymbolWidth[UDAT_STYLE_COUNT] = {
DateFormatSymbols::WIDE, DateFormatSymbols::SHORT, DateFormatSymbols::NARROW
};
@@ -621,14 +621,14 @@ static void loadWeekdayNames(UnicodeString absoluteUnits[UDAT_STYLE_COUNT]
[UDAT_ABSOLUTE_UNIT_COUNT][UDAT_DIRECTION_COUNT],
const char* localeId,
UErrorCode& status) {
- if (U_FAILURE(status)) {
- return;
- }
+ if (U_FAILURE(status)) {
+ return;
+ }
Locale locale(localeId);
DateFormatSymbols dfSym(locale, status);
- if (U_FAILURE(status)) {
- return;
- }
+ if (U_FAILURE(status)) {
+ return;
+ }
for (int32_t style = 0; style < UDAT_STYLE_COUNT; ++style) {
DateFormatSymbols::DtWidthType dtfmtWidth = styleToDateFormatSymbolWidth[style];
int32_t count;
@@ -652,9 +652,9 @@ static UBool loadUnitData(
RelDateTimeFmtDataSink sink(cacheData);
ures_getAllItemsWithFallback(resource, "fields", sink, status);
- if (U_FAILURE(status)) {
- return false;
- }
+ if (U_FAILURE(status)) {
+ return false;
+ }
// Get the weekday names from DateFormatSymbols.
loadWeekdayNames(cacheData.absoluteUnits, localeId, status);
@@ -679,7 +679,7 @@ static UBool getDateTimePattern(
.append("/DateTimePatterns", status);
LocalUResourceBundlePointer topLevel(
ures_getByKeyWithFallback(
- resource, pathBuffer.data(), nullptr, &status));
+ resource, pathBuffer.data(), nullptr, &status));
if (U_FAILURE(status)) {
return FALSE;
}
@@ -696,88 +696,88 @@ static UBool getDateTimePattern(
template<> U_I18N_API
const RelativeDateTimeCacheData *LocaleCacheKey<RelativeDateTimeCacheData>::createObject(const void * /*unused*/, UErrorCode &status) const {
const char *localeId = fLoc.getName();
- LocalUResourceBundlePointer topLevel(ures_open(nullptr, localeId, &status));
+ LocalUResourceBundlePointer topLevel(ures_open(nullptr, localeId, &status));
if (U_FAILURE(status)) {
- return nullptr;
+ return nullptr;
}
LocalPointer<RelativeDateTimeCacheData> result(
new RelativeDateTimeCacheData());
if (result.isNull()) {
status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
+ return nullptr;
}
if (!loadUnitData(
topLevel.getAlias(),
*result,
localeId,
status)) {
- return nullptr;
+ return nullptr;
}
UnicodeString dateTimePattern;
if (!getDateTimePattern(topLevel.getAlias(), dateTimePattern, status)) {
- return nullptr;
+ return nullptr;
}
result->adoptCombinedDateAndTime(
new SimpleFormatter(dateTimePattern, 2, 2, status));
if (U_FAILURE(status)) {
- return nullptr;
+ return nullptr;
}
result->addRef();
return result.orphan();
}
-
-
-static constexpr FormattedStringBuilder::Field kRDTNumericField
- = {UFIELD_CATEGORY_RELATIVE_DATETIME, UDAT_REL_NUMERIC_FIELD};
-
-static constexpr FormattedStringBuilder::Field kRDTLiteralField
- = {UFIELD_CATEGORY_RELATIVE_DATETIME, UDAT_REL_LITERAL_FIELD};
-
-class FormattedRelativeDateTimeData : public FormattedValueStringBuilderImpl {
-public:
- FormattedRelativeDateTimeData() : FormattedValueStringBuilderImpl(kRDTNumericField) {}
- virtual ~FormattedRelativeDateTimeData();
-};
-
-FormattedRelativeDateTimeData::~FormattedRelativeDateTimeData() = default;
-
-
-UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(FormattedRelativeDateTime)
-
-
+
+
+static constexpr FormattedStringBuilder::Field kRDTNumericField
+ = {UFIELD_CATEGORY_RELATIVE_DATETIME, UDAT_REL_NUMERIC_FIELD};
+
+static constexpr FormattedStringBuilder::Field kRDTLiteralField
+ = {UFIELD_CATEGORY_RELATIVE_DATETIME, UDAT_REL_LITERAL_FIELD};
+
+class FormattedRelativeDateTimeData : public FormattedValueStringBuilderImpl {
+public:
+ FormattedRelativeDateTimeData() : FormattedValueStringBuilderImpl(kRDTNumericField) {}
+ virtual ~FormattedRelativeDateTimeData();
+};
+
+FormattedRelativeDateTimeData::~FormattedRelativeDateTimeData() = default;
+
+
+UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(FormattedRelativeDateTime)
+
+
RelativeDateTimeFormatter::RelativeDateTimeFormatter(UErrorCode& status) :
- fCache(nullptr),
- fNumberFormat(nullptr),
- fPluralRules(nullptr),
+ fCache(nullptr),
+ fNumberFormat(nullptr),
+ fPluralRules(nullptr),
fStyle(UDAT_STYLE_LONG),
fContext(UDISPCTX_CAPITALIZATION_NONE),
- fOptBreakIterator(nullptr) {
- init(nullptr, nullptr, status);
+ fOptBreakIterator(nullptr) {
+ init(nullptr, nullptr, status);
}
RelativeDateTimeFormatter::RelativeDateTimeFormatter(
const Locale& locale, UErrorCode& status) :
- fCache(nullptr),
- fNumberFormat(nullptr),
- fPluralRules(nullptr),
+ fCache(nullptr),
+ fNumberFormat(nullptr),
+ fPluralRules(nullptr),
fStyle(UDAT_STYLE_LONG),
fContext(UDISPCTX_CAPITALIZATION_NONE),
- fOptBreakIterator(nullptr),
+ fOptBreakIterator(nullptr),
fLocale(locale) {
- init(nullptr, nullptr, status);
+ init(nullptr, nullptr, status);
}
RelativeDateTimeFormatter::RelativeDateTimeFormatter(
const Locale& locale, NumberFormat *nfToAdopt, UErrorCode& status) :
- fCache(nullptr),
- fNumberFormat(nullptr),
- fPluralRules(nullptr),
+ fCache(nullptr),
+ fNumberFormat(nullptr),
+ fPluralRules(nullptr),
fStyle(UDAT_STYLE_LONG),
fContext(UDISPCTX_CAPITALIZATION_NONE),
- fOptBreakIterator(nullptr),
+ fOptBreakIterator(nullptr),
fLocale(locale) {
- init(nfToAdopt, nullptr, status);
+ init(nfToAdopt, nullptr, status);
}
RelativeDateTimeFormatter::RelativeDateTimeFormatter(
@@ -786,12 +786,12 @@ RelativeDateTimeFormatter::RelativeDateTimeFormatter(
UDateRelativeDateTimeFormatterStyle styl,
UDisplayContext capitalizationContext,
UErrorCode& status) :
- fCache(nullptr),
- fNumberFormat(nullptr),
- fPluralRules(nullptr),
+ fCache(nullptr),
+ fNumberFormat(nullptr),
+ fPluralRules(nullptr),
fStyle(styl),
fContext(capitalizationContext),
- fOptBreakIterator(nullptr),
+ fOptBreakIterator(nullptr),
fLocale(locale) {
if (U_FAILURE(status)) {
return;
@@ -807,7 +807,7 @@ RelativeDateTimeFormatter::RelativeDateTimeFormatter(
}
init(nfToAdopt, bi, status);
} else {
- init(nfToAdopt, nullptr, status);
+ init(nfToAdopt, nullptr, status);
}
}
@@ -824,7 +824,7 @@ RelativeDateTimeFormatter::RelativeDateTimeFormatter(
fCache->addRef();
fNumberFormat->addRef();
fPluralRules->addRef();
- if (fOptBreakIterator != nullptr) {
+ if (fOptBreakIterator != nullptr) {
fOptBreakIterator->addRef();
}
}
@@ -844,16 +844,16 @@ RelativeDateTimeFormatter& RelativeDateTimeFormatter::operator=(
}
RelativeDateTimeFormatter::~RelativeDateTimeFormatter() {
- if (fCache != nullptr) {
+ if (fCache != nullptr) {
fCache->removeRef();
}
- if (fNumberFormat != nullptr) {
+ if (fNumberFormat != nullptr) {
fNumberFormat->removeRef();
}
- if (fPluralRules != nullptr) {
+ if (fPluralRules != nullptr) {
fPluralRules->removeRef();
}
- if (fOptBreakIterator != nullptr) {
+ if (fOptBreakIterator != nullptr) {
fOptBreakIterator->removeRef();
}
}
@@ -870,254 +870,254 @@ UDateRelativeDateTimeFormatterStyle RelativeDateTimeFormatter::getFormatStyle()
return fStyle;
}
-
-// To reduce boilerplate code, we use a helper function that forwards variadic
-// arguments to the formatImpl function.
-
-template<typename F, typename... Args>
-UnicodeString& RelativeDateTimeFormatter::doFormat(
- F callback,
- UnicodeString& appendTo,
- UErrorCode& status,
- Args... args) const {
- FormattedRelativeDateTimeData output;
- (this->*callback)(std::forward<Args>(args)..., output, status);
+
+// To reduce boilerplate code, we use a helper function that forwards variadic
+// arguments to the formatImpl function.
+
+template<typename F, typename... Args>
+UnicodeString& RelativeDateTimeFormatter::doFormat(
+ F callback,
+ UnicodeString& appendTo,
+ UErrorCode& status,
+ Args... args) const {
+ FormattedRelativeDateTimeData output;
+ (this->*callback)(std::forward<Args>(args)..., output, status);
if (U_FAILURE(status)) {
return appendTo;
}
- UnicodeString result = output.getStringRef().toUnicodeString();
- return appendTo.append(adjustForContext(result));
-}
-
-template<typename F, typename... Args>
-FormattedRelativeDateTime RelativeDateTimeFormatter::doFormatToValue(
- F callback,
- UErrorCode& status,
- Args... args) const {
- if (!checkNoAdjustForContext(status)) {
- return FormattedRelativeDateTime(status);
- }
- LocalPointer<FormattedRelativeDateTimeData> output(
- new FormattedRelativeDateTimeData(), status);
- if (U_FAILURE(status)) {
- return FormattedRelativeDateTime(status);
- }
- (this->*callback)(std::forward<Args>(args)..., *output, status);
- output->getStringRef().writeTerminator(status);
- return FormattedRelativeDateTime(output.orphan());
-}
-
-UnicodeString& RelativeDateTimeFormatter::format(
- double quantity,
- UDateDirection direction,
- UDateRelativeUnit unit,
- UnicodeString& appendTo,
- UErrorCode& status) const {
- return doFormat(
- &RelativeDateTimeFormatter::formatImpl,
- appendTo,
- status,
- quantity,
- direction,
- unit);
-}
-
-FormattedRelativeDateTime RelativeDateTimeFormatter::formatToValue(
- double quantity,
- UDateDirection direction,
- UDateRelativeUnit unit,
- UErrorCode& status) const {
- return doFormatToValue(
- &RelativeDateTimeFormatter::formatImpl,
- status,
- quantity,
- direction,
- unit);
-}
-
-void RelativeDateTimeFormatter::formatImpl(
- double quantity,
- UDateDirection direction,
- UDateRelativeUnit unit,
- FormattedRelativeDateTimeData& output,
- UErrorCode& status) const {
- if (U_FAILURE(status)) {
- return;
- }
+ UnicodeString result = output.getStringRef().toUnicodeString();
+ return appendTo.append(adjustForContext(result));
+}
+
+template<typename F, typename... Args>
+FormattedRelativeDateTime RelativeDateTimeFormatter::doFormatToValue(
+ F callback,
+ UErrorCode& status,
+ Args... args) const {
+ if (!checkNoAdjustForContext(status)) {
+ return FormattedRelativeDateTime(status);
+ }
+ LocalPointer<FormattedRelativeDateTimeData> output(
+ new FormattedRelativeDateTimeData(), status);
+ if (U_FAILURE(status)) {
+ return FormattedRelativeDateTime(status);
+ }
+ (this->*callback)(std::forward<Args>(args)..., *output, status);
+ output->getStringRef().writeTerminator(status);
+ return FormattedRelativeDateTime(output.orphan());
+}
+
+UnicodeString& RelativeDateTimeFormatter::format(
+ double quantity,
+ UDateDirection direction,
+ UDateRelativeUnit unit,
+ UnicodeString& appendTo,
+ UErrorCode& status) const {
+ return doFormat(
+ &RelativeDateTimeFormatter::formatImpl,
+ appendTo,
+ status,
+ quantity,
+ direction,
+ unit);
+}
+
+FormattedRelativeDateTime RelativeDateTimeFormatter::formatToValue(
+ double quantity,
+ UDateDirection direction,
+ UDateRelativeUnit unit,
+ UErrorCode& status) const {
+ return doFormatToValue(
+ &RelativeDateTimeFormatter::formatImpl,
+ status,
+ quantity,
+ direction,
+ unit);
+}
+
+void RelativeDateTimeFormatter::formatImpl(
+ double quantity,
+ UDateDirection direction,
+ UDateRelativeUnit unit,
+ FormattedRelativeDateTimeData& output,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
if (direction != UDAT_DIRECTION_LAST && direction != UDAT_DIRECTION_NEXT) {
status = U_ILLEGAL_ARGUMENT_ERROR;
- return;
+ return;
}
int32_t bFuture = direction == UDAT_DIRECTION_NEXT ? 1 : 0;
- StandardPlural::Form pluralForm;
- QuantityFormatter::formatAndSelect(
- quantity,
- **fNumberFormat,
- **fPluralRules,
- output.getStringRef(),
- pluralForm,
+ StandardPlural::Form pluralForm;
+ QuantityFormatter::formatAndSelect(
+ quantity,
+ **fNumberFormat,
+ **fPluralRules,
+ output.getStringRef(),
+ pluralForm,
status);
- if (U_FAILURE(status)) {
- return;
- }
+ if (U_FAILURE(status)) {
+ return;
+ }
const SimpleFormatter* formatter =
- fCache->getRelativeUnitFormatter(fStyle, unit, bFuture, pluralForm);
- if (formatter == nullptr) {
+ fCache->getRelativeUnitFormatter(fStyle, unit, bFuture, pluralForm);
+ if (formatter == nullptr) {
// TODO: WARN - look at quantity formatter's action with an error.
status = U_INVALID_FORMAT_ERROR;
- return;
+ return;
}
-
- number::impl::SimpleModifier modifier(*formatter, kRDTLiteralField, false);
- modifier.formatAsPrefixSuffix(
- output.getStringRef(), 0, output.getStringRef().length(), status);
+
+ number::impl::SimpleModifier modifier(*formatter, kRDTLiteralField, false);
+ modifier.formatAsPrefixSuffix(
+ output.getStringRef(), 0, output.getStringRef().length(), status);
}
UnicodeString& RelativeDateTimeFormatter::formatNumeric(
- double offset,
- URelativeDateTimeUnit unit,
- UnicodeString& appendTo,
- UErrorCode& status) const {
- return doFormat(
- &RelativeDateTimeFormatter::formatNumericImpl,
- appendTo,
- status,
- offset,
- unit);
-}
-
-FormattedRelativeDateTime RelativeDateTimeFormatter::formatNumericToValue(
- double offset,
- URelativeDateTimeUnit unit,
- UErrorCode& status) const {
- return doFormatToValue(
- &RelativeDateTimeFormatter::formatNumericImpl,
- status,
- offset,
- unit);
-}
-
-void RelativeDateTimeFormatter::formatNumericImpl(
- double offset,
- URelativeDateTimeUnit unit,
- FormattedRelativeDateTimeData& output,
- UErrorCode& status) const {
+ double offset,
+ URelativeDateTimeUnit unit,
+ UnicodeString& appendTo,
+ UErrorCode& status) const {
+ return doFormat(
+ &RelativeDateTimeFormatter::formatNumericImpl,
+ appendTo,
+ status,
+ offset,
+ unit);
+}
+
+FormattedRelativeDateTime RelativeDateTimeFormatter::formatNumericToValue(
+ double offset,
+ URelativeDateTimeUnit unit,
+ UErrorCode& status) const {
+ return doFormatToValue(
+ &RelativeDateTimeFormatter::formatNumericImpl,
+ status,
+ offset,
+ unit);
+}
+
+void RelativeDateTimeFormatter::formatNumericImpl(
+ double offset,
+ URelativeDateTimeUnit unit,
+ FormattedRelativeDateTimeData& output,
+ UErrorCode& status) const {
if (U_FAILURE(status)) {
- return;
+ return;
}
UDateDirection direction = UDAT_DIRECTION_NEXT;
- if (std::signbit(offset)) { // needed to handle -0.0
+ if (std::signbit(offset)) { // needed to handle -0.0
direction = UDAT_DIRECTION_LAST;
offset = -offset;
}
- if (direction != UDAT_DIRECTION_LAST && direction != UDAT_DIRECTION_NEXT) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return;
- }
- int32_t bFuture = direction == UDAT_DIRECTION_NEXT ? 1 : 0;
-
- StandardPlural::Form pluralForm;
- QuantityFormatter::formatAndSelect(
- offset,
- **fNumberFormat,
- **fPluralRules,
- output.getStringRef(),
- pluralForm,
- status);
- if (U_FAILURE(status)) {
- return;
- }
-
- const SimpleFormatter* formatter =
- fCache->getRelativeDateTimeUnitFormatter(fStyle, unit, bFuture, pluralForm);
- if (formatter == nullptr) {
- // TODO: WARN - look at quantity formatter's action with an error.
- status = U_INVALID_FORMAT_ERROR;
- return;
- }
-
- number::impl::SimpleModifier modifier(*formatter, kRDTLiteralField, false);
- modifier.formatAsPrefixSuffix(
- output.getStringRef(), 0, output.getStringRef().length(), status);
+ if (direction != UDAT_DIRECTION_LAST && direction != UDAT_DIRECTION_NEXT) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ int32_t bFuture = direction == UDAT_DIRECTION_NEXT ? 1 : 0;
+
+ StandardPlural::Form pluralForm;
+ QuantityFormatter::formatAndSelect(
+ offset,
+ **fNumberFormat,
+ **fPluralRules,
+ output.getStringRef(),
+ pluralForm,
+ status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ const SimpleFormatter* formatter =
+ fCache->getRelativeDateTimeUnitFormatter(fStyle, unit, bFuture, pluralForm);
+ if (formatter == nullptr) {
+ // TODO: WARN - look at quantity formatter's action with an error.
+ status = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+
+ number::impl::SimpleModifier modifier(*formatter, kRDTLiteralField, false);
+ modifier.formatAsPrefixSuffix(
+ output.getStringRef(), 0, output.getStringRef().length(), status);
}
UnicodeString& RelativeDateTimeFormatter::format(
- UDateDirection direction,
- UDateAbsoluteUnit unit,
- UnicodeString& appendTo,
- UErrorCode& status) const {
- return doFormat(
- &RelativeDateTimeFormatter::formatAbsoluteImpl,
- appendTo,
- status,
- direction,
- unit);
-}
-
-FormattedRelativeDateTime RelativeDateTimeFormatter::formatToValue(
- UDateDirection direction,
- UDateAbsoluteUnit unit,
- UErrorCode& status) const {
- return doFormatToValue(
- &RelativeDateTimeFormatter::formatAbsoluteImpl,
- status,
- direction,
- unit);
-}
-
-void RelativeDateTimeFormatter::formatAbsoluteImpl(
- UDateDirection direction,
- UDateAbsoluteUnit unit,
- FormattedRelativeDateTimeData& output,
- UErrorCode& status) const {
+ UDateDirection direction,
+ UDateAbsoluteUnit unit,
+ UnicodeString& appendTo,
+ UErrorCode& status) const {
+ return doFormat(
+ &RelativeDateTimeFormatter::formatAbsoluteImpl,
+ appendTo,
+ status,
+ direction,
+ unit);
+}
+
+FormattedRelativeDateTime RelativeDateTimeFormatter::formatToValue(
+ UDateDirection direction,
+ UDateAbsoluteUnit unit,
+ UErrorCode& status) const {
+ return doFormatToValue(
+ &RelativeDateTimeFormatter::formatAbsoluteImpl,
+ status,
+ direction,
+ unit);
+}
+
+void RelativeDateTimeFormatter::formatAbsoluteImpl(
+ UDateDirection direction,
+ UDateAbsoluteUnit unit,
+ FormattedRelativeDateTimeData& output,
+ UErrorCode& status) const {
if (U_FAILURE(status)) {
- return;
+ return;
}
if (unit == UDAT_ABSOLUTE_NOW && direction != UDAT_DIRECTION_PLAIN) {
status = U_ILLEGAL_ARGUMENT_ERROR;
- return;
+ return;
}
// Get string using fallback.
- output.getStringRef().append(
- fCache->getAbsoluteUnitString(fStyle, unit, direction),
- kRDTLiteralField,
- status);
+ output.getStringRef().append(
+ fCache->getAbsoluteUnitString(fStyle, unit, direction),
+ kRDTLiteralField,
+ status);
}
UnicodeString& RelativeDateTimeFormatter::format(
- double offset,
- URelativeDateTimeUnit unit,
- UnicodeString& appendTo,
- UErrorCode& status) const {
- return doFormat(
- &RelativeDateTimeFormatter::formatRelativeImpl,
- appendTo,
- status,
- offset,
- unit);
-}
-
-FormattedRelativeDateTime RelativeDateTimeFormatter::formatToValue(
- double offset,
- URelativeDateTimeUnit unit,
- UErrorCode& status) const {
- return doFormatToValue(
- &RelativeDateTimeFormatter::formatRelativeImpl,
- status,
- offset,
- unit);
-}
-
-void RelativeDateTimeFormatter::formatRelativeImpl(
- double offset,
- URelativeDateTimeUnit unit,
- FormattedRelativeDateTimeData& output,
- UErrorCode& status) const {
+ double offset,
+ URelativeDateTimeUnit unit,
+ UnicodeString& appendTo,
+ UErrorCode& status) const {
+ return doFormat(
+ &RelativeDateTimeFormatter::formatRelativeImpl,
+ appendTo,
+ status,
+ offset,
+ unit);
+}
+
+FormattedRelativeDateTime RelativeDateTimeFormatter::formatToValue(
+ double offset,
+ URelativeDateTimeUnit unit,
+ UErrorCode& status) const {
+ return doFormatToValue(
+ &RelativeDateTimeFormatter::formatRelativeImpl,
+ status,
+ offset,
+ unit);
+}
+
+void RelativeDateTimeFormatter::formatRelativeImpl(
+ double offset,
+ URelativeDateTimeUnit unit,
+ FormattedRelativeDateTimeData& output,
+ UErrorCode& status) const {
if (U_FAILURE(status)) {
- return;
+ return;
}
// TODO:
// The full implementation of this depends on CLDR data that is not yet available,
@@ -1144,7 +1144,7 @@ void RelativeDateTimeFormatter::formatRelativeImpl(
UDateAbsoluteUnit absunit = UDAT_ABSOLUTE_UNIT_COUNT;
switch (unit) {
case UDAT_REL_UNIT_YEAR: absunit = UDAT_ABSOLUTE_YEAR; break;
- case UDAT_REL_UNIT_QUARTER: absunit = UDAT_ABSOLUTE_QUARTER; break;
+ case UDAT_REL_UNIT_QUARTER: absunit = UDAT_ABSOLUTE_QUARTER; break;
case UDAT_REL_UNIT_MONTH: absunit = UDAT_ABSOLUTE_MONTH; break;
case UDAT_REL_UNIT_WEEK: absunit = UDAT_ABSOLUTE_WEEK; break;
case UDAT_REL_UNIT_DAY: absunit = UDAT_ABSOLUTE_DAY; break;
@@ -1161,18 +1161,18 @@ void RelativeDateTimeFormatter::formatRelativeImpl(
case UDAT_REL_UNIT_THURSDAY: absunit = UDAT_ABSOLUTE_THURSDAY; break;
case UDAT_REL_UNIT_FRIDAY: absunit = UDAT_ABSOLUTE_FRIDAY; break;
case UDAT_REL_UNIT_SATURDAY: absunit = UDAT_ABSOLUTE_SATURDAY; break;
- case UDAT_REL_UNIT_HOUR: absunit = UDAT_ABSOLUTE_HOUR; break;
- case UDAT_REL_UNIT_MINUTE: absunit = UDAT_ABSOLUTE_MINUTE; break;
+ case UDAT_REL_UNIT_HOUR: absunit = UDAT_ABSOLUTE_HOUR; break;
+ case UDAT_REL_UNIT_MINUTE: absunit = UDAT_ABSOLUTE_MINUTE; break;
default: break;
}
if (direction != UDAT_DIRECTION_COUNT && absunit != UDAT_ABSOLUTE_UNIT_COUNT) {
- formatAbsoluteImpl(direction, absunit, output, status);
- if (output.getStringRef().length() != 0) {
- return;
+ formatAbsoluteImpl(direction, absunit, output, status);
+ if (output.getStringRef().length() != 0) {
+ return;
}
}
// otherwise fallback to formatNumeric
- formatNumericImpl(offset, unit, output, status);
+ formatNumericImpl(offset, unit, output, status);
}
UnicodeString& RelativeDateTimeFormatter::combineDateAndTime(
@@ -1182,33 +1182,33 @@ UnicodeString& RelativeDateTimeFormatter::combineDateAndTime(
timeString, relativeDateString, appendTo, status);
}
-UnicodeString& RelativeDateTimeFormatter::adjustForContext(UnicodeString &str) const {
- if (fOptBreakIterator == nullptr
+UnicodeString& RelativeDateTimeFormatter::adjustForContext(UnicodeString &str) const {
+ if (fOptBreakIterator == nullptr
|| str.length() == 0 || !u_islower(str.char32At(0))) {
- return str;
+ return str;
}
// Must guarantee that one thread at a time accesses the shared break
// iterator.
- static UMutex gBrkIterMutex;
+ static UMutex gBrkIterMutex;
Mutex lock(&gBrkIterMutex);
str.toTitle(
fOptBreakIterator->get(),
fLocale,
U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
- return str;
-}
-
-UBool RelativeDateTimeFormatter::checkNoAdjustForContext(UErrorCode& status) const {
- // This is unsupported because it's hard to keep fields in sync with title
- // casing. The code could be written and tested if there is demand.
- if (fOptBreakIterator != nullptr) {
- status = U_UNSUPPORTED_ERROR;
- return FALSE;
- }
- return TRUE;
+ return str;
}
+UBool RelativeDateTimeFormatter::checkNoAdjustForContext(UErrorCode& status) const {
+ // This is unsupported because it's hard to keep fields in sync with title
+ // casing. The code could be written and tested if there is demand.
+ if (fOptBreakIterator != nullptr) {
+ status = U_UNSUPPORTED_ERROR;
+ return FALSE;
+ }
+ return TRUE;
+}
+
void RelativeDateTimeFormatter::init(
NumberFormat *nfToAdopt,
BreakIterator *biToAdopt,
@@ -1236,7 +1236,7 @@ void RelativeDateTimeFormatter::init(
shared->removeRef();
} else {
SharedNumberFormat *shared = new SharedNumberFormat(nf.getAlias());
- if (shared == nullptr) {
+ if (shared == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
@@ -1247,7 +1247,7 @@ void RelativeDateTimeFormatter::init(
SharedObject::clearPtr(fOptBreakIterator);
} else {
SharedBreakIterator *shared = new SharedBreakIterator(bi.getAlias());
- if (shared == nullptr) {
+ if (shared == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
@@ -1262,17 +1262,17 @@ U_NAMESPACE_END
U_NAMESPACE_USE
-
-// Magic number: "FRDT" (FormattedRelativeDateTime) in ASCII
-UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL(
- FormattedRelativeDateTime,
- UFormattedRelativeDateTime,
- UFormattedRelativeDateTimeImpl,
- UFormattedRelativeDateTimeApiHelper,
- ureldatefmt,
- 0x46524454)
-
-
+
+// Magic number: "FRDT" (FormattedRelativeDateTime) in ASCII
+UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL(
+ FormattedRelativeDateTime,
+ UFormattedRelativeDateTime,
+ UFormattedRelativeDateTimeImpl,
+ UFormattedRelativeDateTimeApiHelper,
+ ureldatefmt,
+ 0x46524454)
+
+
U_CAPI URelativeDateTimeFormatter* U_EXPORT2
ureldatefmt_open( const char* locale,
UNumberFormat* nfToAdopt,
@@ -1281,13 +1281,13 @@ ureldatefmt_open( const char* locale,
UErrorCode* status )
{
if (U_FAILURE(*status)) {
- return nullptr;
+ return nullptr;
}
LocalPointer<RelativeDateTimeFormatter> formatter(new RelativeDateTimeFormatter(Locale(locale),
(NumberFormat*)nfToAdopt, width,
capitalizationContext, *status), *status);
if (U_FAILURE(*status)) {
- return nullptr;
+ return nullptr;
}
return (URelativeDateTimeFormatter*)formatter.orphan();
}
@@ -1309,13 +1309,13 @@ ureldatefmt_formatNumeric( const URelativeDateTimeFormatter* reldatefmt,
if (U_FAILURE(*status)) {
return 0;
}
- if (result == nullptr ? resultCapacity != 0 : resultCapacity < 0) {
+ if (result == nullptr ? resultCapacity != 0 : resultCapacity < 0) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
return 0;
}
UnicodeString res;
- if (result != nullptr) {
- // nullptr destination for pure preflighting: empty dummy string
+ if (result != nullptr) {
+ // nullptr destination for pure preflighting: empty dummy string
// otherwise, alias the destination buffer (copied from udat_format)
res.setTo(result, 0, resultCapacity);
}
@@ -1326,21 +1326,21 @@ ureldatefmt_formatNumeric( const URelativeDateTimeFormatter* reldatefmt,
return res.extract(result, resultCapacity, *status);
}
-U_STABLE void U_EXPORT2
-ureldatefmt_formatNumericToResult(
- const URelativeDateTimeFormatter* reldatefmt,
- double offset,
- URelativeDateTimeUnit unit,
- UFormattedRelativeDateTime* result,
- UErrorCode* status) {
- if (U_FAILURE(*status)) {
- return;
- }
- auto* fmt = reinterpret_cast<const RelativeDateTimeFormatter*>(reldatefmt);
- auto* resultImpl = UFormattedRelativeDateTimeApiHelper::validate(result, *status);
- resultImpl->fImpl = fmt->formatNumericToValue(offset, unit, *status);
-}
-
+U_STABLE void U_EXPORT2
+ureldatefmt_formatNumericToResult(
+ const URelativeDateTimeFormatter* reldatefmt,
+ double offset,
+ URelativeDateTimeUnit unit,
+ UFormattedRelativeDateTime* result,
+ UErrorCode* status) {
+ if (U_FAILURE(*status)) {
+ return;
+ }
+ auto* fmt = reinterpret_cast<const RelativeDateTimeFormatter*>(reldatefmt);
+ auto* resultImpl = UFormattedRelativeDateTimeApiHelper::validate(result, *status);
+ resultImpl->fImpl = fmt->formatNumericToValue(offset, unit, *status);
+}
+
U_CAPI int32_t U_EXPORT2
ureldatefmt_format( const URelativeDateTimeFormatter* reldatefmt,
double offset,
@@ -1352,13 +1352,13 @@ ureldatefmt_format( const URelativeDateTimeFormatter* reldatefmt,
if (U_FAILURE(*status)) {
return 0;
}
- if (result == nullptr ? resultCapacity != 0 : resultCapacity < 0) {
+ if (result == nullptr ? resultCapacity != 0 : resultCapacity < 0) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
return 0;
}
UnicodeString res;
- if (result != nullptr) {
- // nullptr destination for pure preflighting: empty dummy string
+ if (result != nullptr) {
+ // nullptr destination for pure preflighting: empty dummy string
// otherwise, alias the destination buffer (copied from udat_format)
res.setTo(result, 0, resultCapacity);
}
@@ -1369,21 +1369,21 @@ ureldatefmt_format( const URelativeDateTimeFormatter* reldatefmt,
return res.extract(result, resultCapacity, *status);
}
-U_DRAFT void U_EXPORT2
-ureldatefmt_formatToResult(
- const URelativeDateTimeFormatter* reldatefmt,
- double offset,
- URelativeDateTimeUnit unit,
- UFormattedRelativeDateTime* result,
- UErrorCode* status) {
- if (U_FAILURE(*status)) {
- return;
- }
- auto* fmt = reinterpret_cast<const RelativeDateTimeFormatter*>(reldatefmt);
- auto* resultImpl = UFormattedRelativeDateTimeApiHelper::validate(result, *status);
- resultImpl->fImpl = fmt->formatToValue(offset, unit, *status);
-}
-
+U_DRAFT void U_EXPORT2
+ureldatefmt_formatToResult(
+ const URelativeDateTimeFormatter* reldatefmt,
+ double offset,
+ URelativeDateTimeUnit unit,
+ UFormattedRelativeDateTime* result,
+ UErrorCode* status) {
+ if (U_FAILURE(*status)) {
+ return;
+ }
+ auto* fmt = reinterpret_cast<const RelativeDateTimeFormatter*>(reldatefmt);
+ auto* resultImpl = UFormattedRelativeDateTimeApiHelper::validate(result, *status);
+ resultImpl->fImpl = fmt->formatToValue(offset, unit, *status);
+}
+
U_CAPI int32_t U_EXPORT2
ureldatefmt_combineDateAndTime( const URelativeDateTimeFormatter* reldatefmt,
const UChar * relativeDateString,
@@ -1397,9 +1397,9 @@ ureldatefmt_combineDateAndTime( const URelativeDateTimeFormatter* reldatefmt,
if (U_FAILURE(*status)) {
return 0;
}
- if (result == nullptr ? resultCapacity != 0 : resultCapacity < 0 ||
- (relativeDateString == nullptr ? relativeDateStringLen != 0 : relativeDateStringLen < -1) ||
- (timeString == nullptr ? timeStringLen != 0 : timeStringLen < -1)) {
+ if (result == nullptr ? resultCapacity != 0 : resultCapacity < 0 ||
+ (relativeDateString == nullptr ? relativeDateStringLen != 0 : relativeDateStringLen < -1) ||
+ (timeString == nullptr ? timeStringLen != 0 : timeStringLen < -1)) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
return 0;
}
diff --git a/contrib/libs/icu/i18n/reldtfmt.cpp b/contrib/libs/icu/i18n/reldtfmt.cpp
index c8ffd04646..161a182f08 100644
--- a/contrib/libs/icu/i18n/reldtfmt.cpp
+++ b/contrib/libs/icu/i18n/reldtfmt.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -20,7 +20,7 @@
#include "unicode/udisplaycontext.h"
#include "unicode/uchar.h"
#include "unicode/brkiter.h"
-#include "unicode/ucasemap.h"
+#include "unicode/ucasemap.h"
#include "reldtfmt.h"
#include "cmemory.h"
#include "uresimp.h"
@@ -51,7 +51,7 @@ RelativeDateFormat::RelativeDateFormat(const RelativeDateFormat& other) :
fCapitalizationBrkIter(NULL)
{
if(other.fDateTimeFormatter != NULL) {
- fDateTimeFormatter = other.fDateTimeFormatter->clone();
+ fDateTimeFormatter = other.fDateTimeFormatter->clone();
}
if(other.fCombinedFormat != NULL) {
fCombinedFormat = new SimpleFormatter(*other.fCombinedFormat);
@@ -131,7 +131,7 @@ RelativeDateFormat::~RelativeDateFormat() {
}
-RelativeDateFormat* RelativeDateFormat::clone() const {
+RelativeDateFormat* RelativeDateFormat::clone() const {
return new RelativeDateFormat(*this);
}
@@ -430,7 +430,7 @@ RelativeDateFormat::setContext(UDisplayContext value, UErrorCode& status)
if ( fCapitalizationBrkIter == NULL && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
(value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && fCapitalizationOfRelativeUnitsForUIListMenu) ||
(value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE && fCapitalizationOfRelativeUnitsForStandAlone)) ) {
- status = U_ZERO_ERROR;
+ status = U_ZERO_ERROR;
fCapitalizationBrkIter = BreakIterator::createSentenceInstance(fLocale, status);
if (U_FAILURE(status)) {
delete fCapitalizationBrkIter;
@@ -456,8 +456,8 @@ RelativeDateFormat::initCapitalizationContextInfo(const Locale& thelocale)
const int32_t * intVector = ures_getIntVector(rb.getAlias(),
&len, &status);
if (U_SUCCESS(status) && intVector != NULL && len >= 2) {
- fCapitalizationOfRelativeUnitsForUIListMenu = static_cast<UBool>(intVector[0]);
- fCapitalizationOfRelativeUnitsForStandAlone = static_cast<UBool>(intVector[1]);
+ fCapitalizationOfRelativeUnitsForUIListMenu = static_cast<UBool>(intVector[0]);
+ fCapitalizationOfRelativeUnitsForStandAlone = static_cast<UBool>(intVector[1]);
}
}
#endif
diff --git a/contrib/libs/icu/i18n/reldtfmt.h b/contrib/libs/icu/i18n/reldtfmt.h
index ff48d3b5c4..2d5ed1bbb9 100644
--- a/contrib/libs/icu/i18n/reldtfmt.h
+++ b/contrib/libs/icu/i18n/reldtfmt.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -71,7 +71,7 @@ public:
* @return A copy of the object.
* @internal ICU 3.8
*/
- virtual RelativeDateFormat* clone() const;
+ virtual RelativeDateFormat* clone() const;
/**
* Return true if the given Format objects are semantically equal. Objects
diff --git a/contrib/libs/icu/i18n/rematch.cpp b/contrib/libs/icu/i18n/rematch.cpp
index 69909faab9..c8f07e7c1b 100644
--- a/contrib/libs/icu/i18n/rematch.cpp
+++ b/contrib/libs/icu/i18n/rematch.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**************************************************************************
@@ -177,7 +177,7 @@ RegexMatcher::~RegexMatcher() {
#if UCONFIG_NO_BREAK_ITERATION==0
delete fWordBreakItr;
- delete fGCBreakItr;
+ delete fGCBreakItr;
#endif
}
@@ -223,7 +223,7 @@ void RegexMatcher::init(UErrorCode &status) {
fDeferredStatus = status;
fData = fSmallData;
fWordBreakItr = NULL;
- fGCBreakItr = NULL;
+ fGCBreakItr = NULL;
fStack = NULL;
fInputText = NULL;
@@ -431,7 +431,7 @@ RegexMatcher &RegexMatcher::appendReplacement(UText *dest,
(nextChar >= 0x31 && nextChar <= 0x39)) { // 0..9
groupName.append(nextChar);
} else if (nextChar == RIGHTBRACKET) {
- groupNum = fPattern->fNamedCaptureMap ? uhash_geti(fPattern->fNamedCaptureMap, &groupName) : 0;
+ groupNum = fPattern->fNamedCaptureMap ? uhash_geti(fPattern->fNamedCaptureMap, &groupName) : 0;
if (groupNum == 0) {
status = U_REGEX_INVALID_CAPTURE_GROUP_NAME;
}
@@ -440,7 +440,7 @@ RegexMatcher &RegexMatcher::appendReplacement(UText *dest,
status = U_REGEX_INVALID_CAPTURE_GROUP_NAME;
}
}
-
+
} else if (u_isdigit(nextChar)) {
// $n Scan for a capture group number
int32_t numCaptureGroups = fPattern->fGroupMap->size();
@@ -461,7 +461,7 @@ RegexMatcher &RegexMatcher::appendReplacement(UText *dest,
break;
}
(void)UTEXT_NEXT32(replacement);
- groupNum=groupNum*10 + nextDigitVal;
+ groupNum=groupNum*10 + nextDigitVal;
++numDigits;
}
} else {
@@ -719,7 +719,7 @@ UBool RegexMatcher::find(UErrorCode &status) {
if (findProgressInterrupt(startPos, status))
return FALSE;
}
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
case START_START:
// Matches are only possible at the start of the input string
@@ -767,7 +767,7 @@ UBool RegexMatcher::find(UErrorCode &status) {
return FALSE;
}
}
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
case START_STRING:
case START_CHAR:
@@ -799,11 +799,11 @@ UBool RegexMatcher::find(UErrorCode &status) {
return FALSE;
}
}
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
case START_LINE:
{
- UChar32 ch;
+ UChar32 ch;
if (startPos == fAnchorStart) {
MatchAt(startPos, FALSE, status);
if (U_FAILURE(status)) {
@@ -813,17 +813,17 @@ UBool RegexMatcher::find(UErrorCode &status) {
return TRUE;
}
UTEXT_SETNATIVEINDEX(fInputText, startPos);
- ch = UTEXT_NEXT32(fInputText);
+ ch = UTEXT_NEXT32(fInputText);
startPos = UTEXT_GETNATIVEINDEX(fInputText);
} else {
UTEXT_SETNATIVEINDEX(fInputText, startPos);
- ch = UTEXT_PREVIOUS32(fInputText);
+ ch = UTEXT_PREVIOUS32(fInputText);
UTEXT_SETNATIVEINDEX(fInputText, startPos);
}
if (fPattern->fFlags & UREGEX_UNIX_LINES) {
for (;;) {
- if (ch == 0x0a) {
+ if (ch == 0x0a) {
MatchAt(startPos, FALSE, status);
if (U_FAILURE(status)) {
return FALSE;
@@ -838,7 +838,7 @@ UBool RegexMatcher::find(UErrorCode &status) {
fHitEnd = TRUE;
return FALSE;
}
- ch = UTEXT_NEXT32(fInputText);
+ ch = UTEXT_NEXT32(fInputText);
startPos = UTEXT_GETNATIVEINDEX(fInputText);
// Note that it's perfectly OK for a pattern to have a zero-length
// match at the end of a string, so we must make sure that the loop
@@ -848,8 +848,8 @@ UBool RegexMatcher::find(UErrorCode &status) {
}
} else {
for (;;) {
- if (isLineTerminator(ch)) {
- if (ch == 0x0d && startPos < fActiveLimit && UTEXT_CURRENT32(fInputText) == 0x0a) {
+ if (isLineTerminator(ch)) {
+ if (ch == 0x0d && startPos < fActiveLimit && UTEXT_CURRENT32(fInputText) == 0x0a) {
(void)UTEXT_NEXT32(fInputText);
startPos = UTEXT_GETNATIVEINDEX(fInputText);
}
@@ -867,7 +867,7 @@ UBool RegexMatcher::find(UErrorCode &status) {
fHitEnd = TRUE;
return FALSE;
}
- ch = UTEXT_NEXT32(fInputText);
+ ch = UTEXT_NEXT32(fInputText);
startPos = UTEXT_GETNATIVEINDEX(fInputText);
// Note that it's perfectly OK for a pattern to have a zero-length
// match at the end of a string, so we must make sure that the loop
@@ -879,10 +879,10 @@ UBool RegexMatcher::find(UErrorCode &status) {
}
default:
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
@@ -993,7 +993,7 @@ UBool RegexMatcher::findUsingChunk(UErrorCode &status) {
if (findProgressInterrupt(startPos, status))
return FALSE;
}
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
case START_START:
// Matches are only possible at the start of the input string
@@ -1035,7 +1035,7 @@ UBool RegexMatcher::findUsingChunk(UErrorCode &status) {
return FALSE;
}
}
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
case START_STRING:
case START_CHAR:
@@ -1064,11 +1064,11 @@ UBool RegexMatcher::findUsingChunk(UErrorCode &status) {
return FALSE;
}
}
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
case START_LINE:
{
- UChar32 ch;
+ UChar32 ch;
if (startPos == fAnchorStart) {
MatchChunkAt(startPos, FALSE, status);
if (U_FAILURE(status)) {
@@ -1082,8 +1082,8 @@ UBool RegexMatcher::findUsingChunk(UErrorCode &status) {
if (fPattern->fFlags & UREGEX_UNIX_LINES) {
for (;;) {
- ch = inputBuf[startPos-1];
- if (ch == 0x0a) {
+ ch = inputBuf[startPos-1];
+ if (ch == 0x0a) {
MatchChunkAt(startPos, FALSE, status);
if (U_FAILURE(status)) {
return FALSE;
@@ -1106,9 +1106,9 @@ UBool RegexMatcher::findUsingChunk(UErrorCode &status) {
}
} else {
for (;;) {
- ch = inputBuf[startPos-1];
- if (isLineTerminator(ch)) {
- if (ch == 0x0d && startPos < fActiveLimit && inputBuf[startPos] == 0x0a) {
+ ch = inputBuf[startPos-1];
+ if (isLineTerminator(ch)) {
+ if (ch == 0x0d && startPos < fActiveLimit && inputBuf[startPos] == 0x0a) {
startPos++;
}
MatchChunkAt(startPos, FALSE, status);
@@ -1135,10 +1135,10 @@ UBool RegexMatcher::findUsingChunk(UErrorCode &status) {
}
default:
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
@@ -1857,14 +1857,14 @@ RegexMatcher &RegexMatcher::reset(const UnicodeString &input) {
fInputUniStrMaybeMutable = TRUE;
#if UCONFIG_NO_BREAK_ITERATION==0
- if (fWordBreakItr) {
- fWordBreakItr->setText(fInputText, fDeferredStatus);
- }
- if (fGCBreakItr) {
- fGCBreakItr->setText(fInputText, fDeferredStatus);
- }
+ if (fWordBreakItr) {
+ fWordBreakItr->setText(fInputText, fDeferredStatus);
+ }
+ if (fGCBreakItr) {
+ fGCBreakItr->setText(fInputText, fDeferredStatus);
+ }
#endif
-
+
return *this;
}
@@ -1882,12 +1882,12 @@ RegexMatcher &RegexMatcher::reset(UText *input) {
fInput = NULL;
#if UCONFIG_NO_BREAK_ITERATION==0
- if (fWordBreakItr) {
- fWordBreakItr->setText(input, fDeferredStatus);
- }
- if (fGCBreakItr) {
- fGCBreakItr->setText(fInputText, fDeferredStatus);
- }
+ if (fWordBreakItr) {
+ fWordBreakItr->setText(input, fDeferredStatus);
+ }
+ if (fGCBreakItr) {
+ fGCBreakItr->setText(fInputText, fDeferredStatus);
+ }
#endif
}
reset();
@@ -2076,7 +2076,7 @@ int32_t RegexMatcher::split(UText *input,
//
if (U_FAILURE(status)) {
return 0;
- }
+ }
if (destCapacity < 1) {
status = U_ILLEGAL_ARGUMENT_ERROR;
@@ -2192,7 +2192,7 @@ int32_t RegexMatcher::split(UText *input,
break;
}
i++;
- dest[i] = utext_extract_replace(fInputText, dest[i],
+ dest[i] = utext_extract_replace(fInputText, dest[i],
start64(groupNum, status), end64(groupNum, status), &status);
}
@@ -2205,7 +2205,7 @@ int32_t RegexMatcher::split(UText *input,
if (dest[i] == NULL) {
dest[i] = utext_openUChars(NULL, NULL, 0, &status);
} else {
- static const UChar emptyString[] = {(UChar)0};
+ static const UChar emptyString[] = {(UChar)0};
utext_replace(dest[i], 0, utext_nativeLength(dest[i]), emptyString, 0, &status);
}
}
@@ -2549,7 +2549,7 @@ UBool RegexMatcher::isWordBoundary(int64_t pos) {
// Current char is a combining one. Not a boundary.
return FALSE;
}
- cIsWord = RegexStaticSets::gStaticSets->fPropSets[URX_ISWORD_SET].contains(c);
+ cIsWord = RegexStaticSets::gStaticSets->fPropSets[URX_ISWORD_SET].contains(c);
}
// Back up until we come to a non-combining char, determine whether
@@ -2562,7 +2562,7 @@ UBool RegexMatcher::isWordBoundary(int64_t pos) {
UChar32 prevChar = UTEXT_PREVIOUS32(fInputText);
if (!(u_hasBinaryProperty(prevChar, UCHAR_GRAPHEME_EXTEND)
|| u_charType(prevChar) == U_FORMAT_CHAR)) {
- prevCIsWord = RegexStaticSets::gStaticSets->fPropSets[URX_ISWORD_SET].contains(prevChar);
+ prevCIsWord = RegexStaticSets::gStaticSets->fPropSets[URX_ISWORD_SET].contains(prevChar);
break;
}
}
@@ -2587,7 +2587,7 @@ UBool RegexMatcher::isChunkWordBoundary(int32_t pos) {
// Current char is a combining one. Not a boundary.
return FALSE;
}
- cIsWord = RegexStaticSets::gStaticSets->fPropSets[URX_ISWORD_SET].contains(c);
+ cIsWord = RegexStaticSets::gStaticSets->fPropSets[URX_ISWORD_SET].contains(c);
}
// Back up until we come to a non-combining char, determine whether
@@ -2601,7 +2601,7 @@ UBool RegexMatcher::isChunkWordBoundary(int32_t pos) {
U16_PREV(inputBuf, fLookStart, pos, prevChar);
if (!(u_hasBinaryProperty(prevChar, UCHAR_GRAPHEME_EXTEND)
|| u_charType(prevChar) == U_FORMAT_CHAR)) {
- prevCIsWord = RegexStaticSets::gStaticSets->fPropSets[URX_ISWORD_SET].contains(prevChar);
+ prevCIsWord = RegexStaticSets::gStaticSets->fPropSets[URX_ISWORD_SET].contains(prevChar);
break;
}
}
@@ -2618,24 +2618,24 @@ UBool RegexMatcher::isChunkWordBoundary(int32_t pos) {
// parameters: pos - the current position in the input buffer
//
//--------------------------------------------------------------------------------
-UBool RegexMatcher::isUWordBoundary(int64_t pos, UErrorCode &status) {
+UBool RegexMatcher::isUWordBoundary(int64_t pos, UErrorCode &status) {
UBool returnVal = FALSE;
-
+
#if UCONFIG_NO_BREAK_ITERATION==0
- // Note: this point will never be reached if break iteration is configured out.
- // Regex patterns that would require this function will fail to compile.
+ // Note: this point will never be reached if break iteration is configured out.
+ // Regex patterns that would require this function will fail to compile.
// If we haven't yet created a break iterator for this matcher, do it now.
- if (fWordBreakItr == nullptr) {
- fWordBreakItr = BreakIterator::createWordInstance(Locale::getEnglish(), status);
- if (U_FAILURE(status)) {
+ if (fWordBreakItr == nullptr) {
+ fWordBreakItr = BreakIterator::createWordInstance(Locale::getEnglish(), status);
+ if (U_FAILURE(status)) {
return FALSE;
}
- fWordBreakItr->setText(fInputText, status);
+ fWordBreakItr->setText(fInputText, status);
}
- // Note: zero width boundary tests like \b see through transparent region bounds,
- // which is why fLookLimit is used here, rather than fActiveLimit.
+ // Note: zero width boundary tests like \b see through transparent region bounds,
+ // which is why fLookLimit is used here, rather than fActiveLimit.
if (pos >= fLookLimit) {
fHitEnd = TRUE;
returnVal = TRUE; // With Unicode word rules, only positions within the interior of "real"
@@ -2648,30 +2648,30 @@ UBool RegexMatcher::isUWordBoundary(int64_t pos, UErrorCode &status) {
return returnVal;
}
-
-int64_t RegexMatcher::followingGCBoundary(int64_t pos, UErrorCode &status) {
- int64_t result = pos;
-
-#if UCONFIG_NO_BREAK_ITERATION==0
- // Note: this point will never be reached if break iteration is configured out.
- // Regex patterns that would require this function will fail to compile.
-
- // If we haven't yet created a break iterator for this matcher, do it now.
- if (fGCBreakItr == nullptr) {
- fGCBreakItr = BreakIterator::createCharacterInstance(Locale::getEnglish(), status);
- if (U_FAILURE(status)) {
- return pos;
- }
- fGCBreakItr->setText(fInputText, status);
- }
- result = fGCBreakItr->following(pos);
- if (result == BreakIterator::DONE) {
- result = pos;
- }
-#endif
- return result;
-}
-
+
+int64_t RegexMatcher::followingGCBoundary(int64_t pos, UErrorCode &status) {
+ int64_t result = pos;
+
+#if UCONFIG_NO_BREAK_ITERATION==0
+ // Note: this point will never be reached if break iteration is configured out.
+ // Regex patterns that would require this function will fail to compile.
+
+ // If we haven't yet created a break iterator for this matcher, do it now.
+ if (fGCBreakItr == nullptr) {
+ fGCBreakItr = BreakIterator::createCharacterInstance(Locale::getEnglish(), status);
+ if (U_FAILURE(status)) {
+ return pos;
+ }
+ fGCBreakItr->setText(fInputText, status);
+ }
+ result = fGCBreakItr->following(pos);
+ if (result == BreakIterator::DONE) {
+ result = pos;
+ }
+#endif
+ return result;
+}
+
//--------------------------------------------------------------------------------
//
// IncrementTime This function is called once each TIMER_INITIAL_VALUE state
@@ -2802,7 +2802,7 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
int64_t *pat = fPattern->fCompiledPat->getBuffer();
const UChar *litText = fPattern->fLiteralText.getBuffer();
- UVector *fSets = fPattern->fSets;
+ UVector *fSets = fPattern->fSets;
fFrameSize = fPattern->fFrameSize;
REStackFrame *fp = resetStack();
@@ -3112,7 +3112,7 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
case URX_BACKSLASH_BU: // Test for word boundaries, Unicode-style
{
- UBool success = isUWordBoundary(fp->fInputIdx, status);
+ UBool success = isUWordBoundary(fp->fInputIdx, status);
success ^= (UBool)(opValue != 0); // flip sense for \B
if (!success) {
fp = (REStackFrame *)fStack->popFrame(fFrameSize);
@@ -3214,21 +3214,21 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
case URX_BACKSLASH_X:
- // Match a Grapheme, as defined by Unicode UAX 29.
+ // Match a Grapheme, as defined by Unicode UAX 29.
- // Fail if at end of input
- if (fp->fInputIdx >= fActiveLimit) {
- fHitEnd = TRUE;
- fp = (REStackFrame *)fStack->popFrame(fFrameSize);
+ // Fail if at end of input
+ if (fp->fInputIdx >= fActiveLimit) {
+ fHitEnd = TRUE;
+ fp = (REStackFrame *)fStack->popFrame(fFrameSize);
break;
}
- fp->fInputIdx = followingGCBoundary(fp->fInputIdx, status);
- if (fp->fInputIdx >= fActiveLimit) {
- fHitEnd = TRUE;
- fp->fInputIdx = fActiveLimit;
- }
- break;
+ fp->fInputIdx = followingGCBoundary(fp->fInputIdx, status);
+ if (fp->fInputIdx >= fActiveLimit) {
+ fHitEnd = TRUE;
+ fp->fInputIdx = fActiveLimit;
+ }
+ break;
case URX_BACKSLASH_Z: // Test for end of Input
@@ -3262,13 +3262,13 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
UTEXT_SETNATIVEINDEX(fInputText, fp->fInputIdx);
UChar32 c = UTEXT_NEXT32(fInputText);
if (c < 256) {
- Regex8BitSet &s8 = RegexStaticSets::gStaticSets->fPropSets8[opValue];
- if (s8.contains(c)) {
+ Regex8BitSet &s8 = RegexStaticSets::gStaticSets->fPropSets8[opValue];
+ if (s8.contains(c)) {
success = !success;
}
} else {
- const UnicodeSet &s = RegexStaticSets::gStaticSets->fPropSets[opValue];
- if (s.contains(c)) {
+ const UnicodeSet &s = RegexStaticSets::gStaticSets->fPropSets[opValue];
+ if (s.contains(c)) {
success = !success;
}
}
@@ -3298,14 +3298,14 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
UChar32 c = UTEXT_NEXT32(fInputText);
if (c < 256) {
- Regex8BitSet &s8 = RegexStaticSets::gStaticSets->fPropSets8[opValue];
- if (s8.contains(c) == FALSE) {
+ Regex8BitSet &s8 = RegexStaticSets::gStaticSets->fPropSets8[opValue];
+ if (s8.contains(c) == FALSE) {
fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
break;
}
} else {
- const UnicodeSet &s = RegexStaticSets::gStaticSets->fPropSets[opValue];
- if (s.contains(c) == FALSE) {
+ const UnicodeSet &s = RegexStaticSets::gStaticSets->fPropSets[opValue];
+ if (s.contains(c) == FALSE) {
fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
break;
}
@@ -3326,7 +3326,7 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
// There is input left. Pick up one char and test it for set membership.
UChar32 c = UTEXT_NEXT32(fInputText);
- U_ASSERT(opValue > 0 && opValue < fSets->size());
+ U_ASSERT(opValue > 0 && opValue < fSets->size());
if (c<256) {
Regex8BitSet *s8 = &fPattern->fSets8[opValue];
if (s8->contains(c)) {
@@ -3334,7 +3334,7 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
break;
}
} else {
- UnicodeSet *s = (UnicodeSet *)fSets->elementAt(opValue);
+ UnicodeSet *s = (UnicodeSet *)fSets->elementAt(opValue);
if (s->contains(c)) {
// The character is in the set. A Match.
fp->fInputIdx = UTEXT_GETNATIVEINDEX(fInputText);
@@ -3516,14 +3516,14 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
}
}
fp = StateSave(fp, fp->fPatIdx, status);
- } else {
- // Increment time-out counter. (StateSave() does it if count >= minCount)
- fTickCounter--;
- if (fTickCounter <= 0) {
- IncrementTime(status); // Re-initializes fTickCounter
- }
- }
-
+ } else {
+ // Increment time-out counter. (StateSave() does it if count >= minCount)
+ fTickCounter--;
+ if (fTickCounter <= 0) {
+ IncrementTime(status); // Re-initializes fTickCounter
+ }
+ }
+
fp->fPatIdx = opValue + 4; // Loop back.
}
break;
@@ -3580,11 +3580,11 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
// We haven't met the minimum number of matches yet.
// Loop back for another one.
fp->fPatIdx = opValue + 4; // Loop back.
- // Increment time-out counter. (StateSave() does it if count >= minCount)
- fTickCounter--;
- if (fTickCounter <= 0) {
- IncrementTime(status); // Re-initializes fTickCounter
- }
+ // Increment time-out counter. (StateSave() does it if count >= minCount)
+ fTickCounter--;
+ if (fTickCounter <= 0) {
+ IncrementTime(status); // Re-initializes fTickCounter
+ }
} else {
// We do have the minimum number of matches.
@@ -3621,9 +3621,9 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
if (newFP == (int64_t *)fp) {
break;
}
- int32_t j;
- for (j=0; j<fFrameSize; j++) {
- newFP[j] = ((int64_t *)fp)[j];
+ int32_t j;
+ for (j=0; j<fFrameSize; j++) {
+ newFP[j] = ((int64_t *)fp)[j];
}
fp = (REStackFrame *)newFP;
fStack->setSize(newStackSize);
@@ -3757,13 +3757,13 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
case URX_LA_START:
{
- // Entering a look around block.
+ // Entering a look around block.
// Save Stack Ptr, Input Pos.
- U_ASSERT(opValue>=0 && opValue+3<fPattern->fDataSize);
+ U_ASSERT(opValue>=0 && opValue+3<fPattern->fDataSize);
fData[opValue] = fStack->size();
fData[opValue+1] = fp->fInputIdx;
- fData[opValue+2] = fActiveStart;
- fData[opValue+3] = fActiveLimit;
+ fData[opValue+2] = fActiveStart;
+ fData[opValue+3] = fActiveLimit;
fActiveStart = fLookStart; // Set the match region change for
fActiveLimit = fLookLimit; // transparent bounds.
}
@@ -3773,7 +3773,7 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
{
// Leaving a look-ahead block.
// restore Stack Ptr, Input Pos to positions they had on entry to block.
- U_ASSERT(opValue>=0 && opValue+3<fPattern->fDataSize);
+ U_ASSERT(opValue>=0 && opValue+3<fPattern->fDataSize);
int32_t stackSize = fStack->size();
int32_t newStackSize =(int32_t)fData[opValue];
U_ASSERT(stackSize >= newStackSize);
@@ -3782,9 +3782,9 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
// This makes the capture groups from within the look-ahead
// expression available.
int64_t *newFP = fStack->getBuffer() + newStackSize - fFrameSize;
- int32_t j;
- for (j=0; j<fFrameSize; j++) {
- newFP[j] = ((int64_t *)fp)[j];
+ int32_t j;
+ for (j=0; j<fFrameSize; j++) {
+ newFP[j] = ((int64_t *)fp)[j];
}
fp = (REStackFrame *)newFP;
fStack->setSize(newStackSize);
@@ -3793,10 +3793,10 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
// Restore the active region bounds in the input string; they may have
// been changed because of transparent bounds on a Region.
- fActiveStart = fData[opValue+2];
- fActiveLimit = fData[opValue+3];
- U_ASSERT(fActiveStart >= 0);
- U_ASSERT(fActiveLimit <= fInputLength);
+ fActiveStart = fData[opValue+2];
+ fActiveLimit = fData[opValue+3];
+ U_ASSERT(fActiveStart >= 0);
+ U_ASSERT(fActiveLimit <= fInputLength);
}
break;
@@ -3872,19 +3872,19 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
case URX_LB_START:
{
// Entering a look-behind block.
- // Save Stack Ptr, Input Pos and active input region.
+ // Save Stack Ptr, Input Pos and active input region.
// TODO: implement transparent bounds. Ticket #6067
- U_ASSERT(opValue>=0 && opValue+4<fPattern->fDataSize);
+ U_ASSERT(opValue>=0 && opValue+4<fPattern->fDataSize);
fData[opValue] = fStack->size();
fData[opValue+1] = fp->fInputIdx;
// Save input string length, then reset to pin any matches to end at
// the current position.
- fData[opValue+2] = fActiveStart;
+ fData[opValue+2] = fActiveStart;
fData[opValue+3] = fActiveLimit;
- fActiveStart = fRegionStart;
+ fActiveStart = fRegionStart;
fActiveLimit = fp->fInputIdx;
- // Init the variable containing the start index for attempted matches.
- fData[opValue+4] = -1;
+ // Init the variable containing the start index for attempted matches.
+ fData[opValue+4] = -1;
}
break;
@@ -3907,8 +3907,8 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
U_ASSERT(minML >= 0);
// Fetch (from data) the last input index where a match was attempted.
- U_ASSERT(opValue>=0 && opValue+4<fPattern->fDataSize);
- int64_t &lbStartIdx = fData[opValue+4];
+ U_ASSERT(opValue>=0 && opValue+4<fPattern->fDataSize);
+ int64_t &lbStartIdx = fData[opValue+4];
if (lbStartIdx < 0) {
// First time through loop.
lbStartIdx = fp->fInputIdx - minML;
@@ -3934,10 +3934,10 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
// getting a match. Backtrack out, and out of the
// Look Behind altogether.
fp = (REStackFrame *)fStack->popFrame(fFrameSize);
- fActiveStart = fData[opValue+2];
- fActiveLimit = fData[opValue+3];
- U_ASSERT(fActiveStart >= 0);
- U_ASSERT(fActiveLimit <= fInputLength);
+ fActiveStart = fData[opValue+2];
+ fActiveLimit = fData[opValue+3];
+ U_ASSERT(fActiveStart >= 0);
+ U_ASSERT(fActiveLimit <= fInputLength);
break;
}
@@ -3951,7 +3951,7 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
case URX_LB_END:
// End of a look-behind block, after a successful match.
{
- U_ASSERT(opValue>=0 && opValue+4<fPattern->fDataSize);
+ U_ASSERT(opValue>=0 && opValue+4<fPattern->fDataSize);
if (fp->fInputIdx != fActiveLimit) {
// The look-behind expression matched, but the match did not
// extend all the way to the point that we are looking behind from.
@@ -3962,13 +3962,13 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
break;
}
- // Look-behind match is good. Restore the orignal input string region,
+ // Look-behind match is good. Restore the orignal input string region,
// which had been truncated to pin the end of the lookbehind match to the
// position being looked-behind.
- fActiveStart = fData[opValue+2];
- fActiveLimit = fData[opValue+3];
- U_ASSERT(fActiveStart >= 0);
- U_ASSERT(fActiveLimit <= fInputLength);
+ fActiveStart = fData[opValue+2];
+ fActiveLimit = fData[opValue+3];
+ U_ASSERT(fActiveStart >= 0);
+ U_ASSERT(fActiveLimit <= fInputLength);
}
break;
@@ -3993,8 +3993,8 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
U_ASSERT(continueLoc > fp->fPatIdx);
// Fetch (from data) the last input index where a match was attempted.
- U_ASSERT(opValue>=0 && opValue+4<fPattern->fDataSize);
- int64_t &lbStartIdx = fData[opValue+4];
+ U_ASSERT(opValue>=0 && opValue+4<fPattern->fDataSize);
+ int64_t &lbStartIdx = fData[opValue+4];
if (lbStartIdx < 0) {
// First time through loop.
lbStartIdx = fp->fInputIdx - minML;
@@ -4019,10 +4019,10 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
// We have tried all potential match starting points without
// getting a match, which means that the negative lookbehind as
// a whole has succeeded. Jump forward to the continue location
- fActiveStart = fData[opValue+2];
- fActiveLimit = fData[opValue+3];
- U_ASSERT(fActiveStart >= 0);
- U_ASSERT(fActiveLimit <= fInputLength);
+ fActiveStart = fData[opValue+2];
+ fActiveLimit = fData[opValue+3];
+ U_ASSERT(fActiveStart >= 0);
+ U_ASSERT(fActiveLimit <= fInputLength);
fp->fPatIdx = continueLoc;
break;
}
@@ -4037,7 +4037,7 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
case URX_LBN_END:
// End of a negative look-behind block, after a successful match.
{
- U_ASSERT(opValue>=0 && opValue+4<fPattern->fDataSize);
+ U_ASSERT(opValue>=0 && opValue+4<fPattern->fDataSize);
if (fp->fInputIdx != fActiveLimit) {
// The look-behind expression matched, but the match did not
// extend all the way to the point that we are looking behind from.
@@ -4054,10 +4054,10 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
// Restore the orignal input string length, which had been truncated
// inorder to pin the end of the lookbehind match
// to the position being looked-behind.
- fActiveStart = fData[opValue+2];
- fActiveLimit = fData[opValue+3];
- U_ASSERT(fActiveStart >= 0);
- U_ASSERT(fActiveLimit <= fInputLength);
+ fActiveStart = fData[opValue+2];
+ fActiveLimit = fData[opValue+3];
+ U_ASSERT(fActiveStart >= 0);
+ U_ASSERT(fActiveLimit <= fInputLength);
// Restore original stack position, discarding any state saved
// by the successful pattern match.
@@ -4079,9 +4079,9 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
// This op scans through all matching input.
// The following LOOP_C op emulates stack unwinding if the following pattern fails.
{
- U_ASSERT(opValue > 0 && opValue < fSets->size());
+ U_ASSERT(opValue > 0 && opValue < fSets->size());
Regex8BitSet *s8 = &fPattern->fSets8[opValue];
- UnicodeSet *s = (UnicodeSet *)fSets->elementAt(opValue);
+ UnicodeSet *s = (UnicodeSet *)fSets->elementAt(opValue);
// Loop through input, until either the input is exhausted or
// we reach a character that is not a member of the set.
@@ -4234,7 +4234,7 @@ void RegexMatcher::MatchAt(int64_t startIdx, UBool toEnd, UErrorCode &status) {
default:
// Trouble. The compiled pattern contains an entry with an
// unrecognized type tag.
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
if (U_FAILURE(status)) {
@@ -4306,7 +4306,7 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
int64_t *pat = fPattern->fCompiledPat->getBuffer();
const UChar *litText = fPattern->fLiteralText.getBuffer();
- UVector *fSets = fPattern->fSets;
+ UVector *fSets = fPattern->fSets;
const UChar *inputBuf = fInputText->chunkContents;
@@ -4614,7 +4614,7 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
case URX_BACKSLASH_BU: // Test for word boundaries, Unicode-style
{
- UBool success = isUWordBoundary(fp->fInputIdx, status);
+ UBool success = isUWordBoundary(fp->fInputIdx, status);
success ^= (UBool)(opValue != 0); // flip sense for \B
if (!success) {
fp = (REStackFrame *)fStack->popFrame(fFrameSize);
@@ -4713,7 +4713,7 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
case URX_BACKSLASH_X:
- // Match a Grapheme, as defined by Unicode UAX 29.
+ // Match a Grapheme, as defined by Unicode UAX 29.
// Fail if at end of input
if (fp->fInputIdx >= fActiveLimit) {
@@ -4722,10 +4722,10 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
break;
}
- fp->fInputIdx = followingGCBoundary(fp->fInputIdx, status);
+ fp->fInputIdx = followingGCBoundary(fp->fInputIdx, status);
if (fp->fInputIdx >= fActiveLimit) {
fHitEnd = TRUE;
- fp->fInputIdx = fActiveLimit;
+ fp->fInputIdx = fActiveLimit;
}
break;
@@ -4761,13 +4761,13 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
UChar32 c;
U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, c);
if (c < 256) {
- Regex8BitSet &s8 = RegexStaticSets::gStaticSets->fPropSets8[opValue];
- if (s8.contains(c)) {
+ Regex8BitSet &s8 = RegexStaticSets::gStaticSets->fPropSets8[opValue];
+ if (s8.contains(c)) {
success = !success;
}
} else {
- const UnicodeSet &s = RegexStaticSets::gStaticSets->fPropSets[opValue];
- if (s.contains(c)) {
+ const UnicodeSet &s = RegexStaticSets::gStaticSets->fPropSets[opValue];
+ if (s.contains(c)) {
success = !success;
}
}
@@ -4793,13 +4793,13 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
UChar32 c;
U16_NEXT(inputBuf, fp->fInputIdx, fActiveLimit, c);
if (c < 256) {
- Regex8BitSet &s8 = RegexStaticSets::gStaticSets->fPropSets8[opValue];
- if (s8.contains(c) == FALSE) {
+ Regex8BitSet &s8 = RegexStaticSets::gStaticSets->fPropSets8[opValue];
+ if (s8.contains(c) == FALSE) {
break;
}
} else {
- const UnicodeSet &s = RegexStaticSets::gStaticSets->fPropSets[opValue];
- if (s.contains(c) == FALSE) {
+ const UnicodeSet &s = RegexStaticSets::gStaticSets->fPropSets[opValue];
+ if (s.contains(c) == FALSE) {
break;
}
}
@@ -4816,7 +4816,7 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
break;
}
- U_ASSERT(opValue > 0 && opValue < fSets->size());
+ U_ASSERT(opValue > 0 && opValue < fSets->size());
// There is input left. Pick up one char and test it for set membership.
UChar32 c;
@@ -4828,7 +4828,7 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
break;
}
} else {
- UnicodeSet *s = (UnicodeSet *)fSets->elementAt(opValue);
+ UnicodeSet *s = (UnicodeSet *)fSets->elementAt(opValue);
if (s->contains(c)) {
// The character is in the set. A Match.
break;
@@ -4999,12 +4999,12 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
}
}
fp = StateSave(fp, fp->fPatIdx, status);
- } else {
- // Increment time-out counter. (StateSave() does it if count >= minCount)
- fTickCounter--;
- if (fTickCounter <= 0) {
- IncrementTime(status); // Re-initializes fTickCounter
- }
+ } else {
+ // Increment time-out counter. (StateSave() does it if count >= minCount)
+ fTickCounter--;
+ if (fTickCounter <= 0) {
+ IncrementTime(status); // Re-initializes fTickCounter
+ }
}
fp->fPatIdx = opValue + 4; // Loop back.
}
@@ -5062,10 +5062,10 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
// We haven't met the minimum number of matches yet.
// Loop back for another one.
fp->fPatIdx = opValue + 4; // Loop back.
- fTickCounter--;
- if (fTickCounter <= 0) {
- IncrementTime(status); // Re-initializes fTickCounter
- }
+ fTickCounter--;
+ if (fTickCounter <= 0) {
+ IncrementTime(status); // Re-initializes fTickCounter
+ }
} else {
// We do have the minimum number of matches.
@@ -5102,9 +5102,9 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
if (newFP == (int64_t *)fp) {
break;
}
- int32_t j;
- for (j=0; j<fFrameSize; j++) {
- newFP[j] = ((int64_t *)fp)[j];
+ int32_t j;
+ for (j=0; j<fFrameSize; j++) {
+ newFP[j] = ((int64_t *)fp)[j];
}
fp = (REStackFrame *)newFP;
fStack->setSize(newStackSize);
@@ -5226,13 +5226,13 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
case URX_LA_START:
{
- // Entering a look around block.
+ // Entering a look around block.
// Save Stack Ptr, Input Pos.
- U_ASSERT(opValue>=0 && opValue+3<fPattern->fDataSize);
+ U_ASSERT(opValue>=0 && opValue+3<fPattern->fDataSize);
fData[opValue] = fStack->size();
fData[opValue+1] = fp->fInputIdx;
- fData[opValue+2] = fActiveStart;
- fData[opValue+3] = fActiveLimit;
+ fData[opValue+2] = fActiveStart;
+ fData[opValue+3] = fActiveLimit;
fActiveStart = fLookStart; // Set the match region change for
fActiveLimit = fLookLimit; // transparent bounds.
}
@@ -5240,9 +5240,9 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
case URX_LA_END:
{
- // Leaving a look around block.
+ // Leaving a look around block.
// restore Stack Ptr, Input Pos to positions they had on entry to block.
- U_ASSERT(opValue>=0 && opValue+3<fPattern->fDataSize);
+ U_ASSERT(opValue>=0 && opValue+3<fPattern->fDataSize);
int32_t stackSize = fStack->size();
int32_t newStackSize = (int32_t)fData[opValue];
U_ASSERT(stackSize >= newStackSize);
@@ -5251,9 +5251,9 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
// This makes the capture groups from within the look-ahead
// expression available.
int64_t *newFP = fStack->getBuffer() + newStackSize - fFrameSize;
- int32_t j;
- for (j=0; j<fFrameSize; j++) {
- newFP[j] = ((int64_t *)fp)[j];
+ int32_t j;
+ for (j=0; j<fFrameSize; j++) {
+ newFP[j] = ((int64_t *)fp)[j];
}
fp = (REStackFrame *)newFP;
fStack->setSize(newStackSize);
@@ -5262,10 +5262,10 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
// Restore the active region bounds in the input string; they may have
// been changed because of transparent bounds on a Region.
- fActiveStart = fData[opValue+2];
- fActiveLimit = fData[opValue+3];
- U_ASSERT(fActiveStart >= 0);
- U_ASSERT(fActiveLimit <= fInputLength);
+ fActiveStart = fData[opValue+2];
+ fActiveLimit = fData[opValue+3];
+ U_ASSERT(fActiveStart >= 0);
+ U_ASSERT(fActiveLimit <= fInputLength);
}
break;
@@ -5328,19 +5328,19 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
case URX_LB_START:
{
// Entering a look-behind block.
- // Save Stack Ptr, Input Pos and active input region.
+ // Save Stack Ptr, Input Pos and active input region.
// TODO: implement transparent bounds. Ticket #6067
- U_ASSERT(opValue>=0 && opValue+4<fPattern->fDataSize);
+ U_ASSERT(opValue>=0 && opValue+4<fPattern->fDataSize);
fData[opValue] = fStack->size();
fData[opValue+1] = fp->fInputIdx;
// Save input string length, then reset to pin any matches to end at
// the current position.
- fData[opValue+2] = fActiveStart;
+ fData[opValue+2] = fActiveStart;
fData[opValue+3] = fActiveLimit;
- fActiveStart = fRegionStart;
+ fActiveStart = fRegionStart;
fActiveLimit = fp->fInputIdx;
- // Init the variable containing the start index for attempted matches.
- fData[opValue+4] = -1;
+ // Init the variable containing the start index for attempted matches.
+ fData[opValue+4] = -1;
}
break;
@@ -5358,12 +5358,12 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
U_ASSERT(minML >= 0);
// Fetch (from data) the last input index where a match was attempted.
- U_ASSERT(opValue>=0 && opValue+4<fPattern->fDataSize);
- int64_t &lbStartIdx = fData[opValue+4];
+ U_ASSERT(opValue>=0 && opValue+4<fPattern->fDataSize);
+ int64_t &lbStartIdx = fData[opValue+4];
if (lbStartIdx < 0) {
// First time through loop.
lbStartIdx = fp->fInputIdx - minML;
- if (lbStartIdx > 0 && lbStartIdx < fInputLength) {
+ if (lbStartIdx > 0 && lbStartIdx < fInputLength) {
U16_SET_CP_START(inputBuf, 0, lbStartIdx);
}
} else {
@@ -5381,10 +5381,10 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
// getting a match. Backtrack out, and out of the
// Look Behind altogether.
fp = (REStackFrame *)fStack->popFrame(fFrameSize);
- fActiveStart = fData[opValue+2];
- fActiveLimit = fData[opValue+3];
- U_ASSERT(fActiveStart >= 0);
- U_ASSERT(fActiveLimit <= fInputLength);
+ fActiveStart = fData[opValue+2];
+ fActiveLimit = fData[opValue+3];
+ U_ASSERT(fActiveStart >= 0);
+ U_ASSERT(fActiveLimit <= fInputLength);
break;
}
@@ -5398,7 +5398,7 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
case URX_LB_END:
// End of a look-behind block, after a successful match.
{
- U_ASSERT(opValue>=0 && opValue+4<fPattern->fDataSize);
+ U_ASSERT(opValue>=0 && opValue+4<fPattern->fDataSize);
if (fp->fInputIdx != fActiveLimit) {
// The look-behind expression matched, but the match did not
// extend all the way to the point that we are looking behind from.
@@ -5409,13 +5409,13 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
break;
}
- // Look-behind match is good. Restore the orignal input string region,
+ // Look-behind match is good. Restore the orignal input string region,
// which had been truncated to pin the end of the lookbehind match to the
// position being looked-behind.
- fActiveStart = fData[opValue+2];
- fActiveLimit = fData[opValue+3];
- U_ASSERT(fActiveStart >= 0);
- U_ASSERT(fActiveLimit <= fInputLength);
+ fActiveStart = fData[opValue+2];
+ fActiveLimit = fData[opValue+3];
+ U_ASSERT(fActiveStart >= 0);
+ U_ASSERT(fActiveLimit <= fInputLength);
}
break;
@@ -5435,12 +5435,12 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
U_ASSERT(continueLoc > fp->fPatIdx);
// Fetch (from data) the last input index where a match was attempted.
- U_ASSERT(opValue>=0 && opValue+4<fPattern->fDataSize);
- int64_t &lbStartIdx = fData[opValue+4];
+ U_ASSERT(opValue>=0 && opValue+4<fPattern->fDataSize);
+ int64_t &lbStartIdx = fData[opValue+4];
if (lbStartIdx < 0) {
// First time through loop.
lbStartIdx = fp->fInputIdx - minML;
- if (lbStartIdx > 0 && lbStartIdx < fInputLength) {
+ if (lbStartIdx > 0 && lbStartIdx < fInputLength) {
U16_SET_CP_START(inputBuf, 0, lbStartIdx);
}
} else {
@@ -5457,10 +5457,10 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
// We have tried all potential match starting points without
// getting a match, which means that the negative lookbehind as
// a whole has succeeded. Jump forward to the continue location
- fActiveStart = fData[opValue+2];
- fActiveLimit = fData[opValue+3];
- U_ASSERT(fActiveStart >= 0);
- U_ASSERT(fActiveLimit <= fInputLength);
+ fActiveStart = fData[opValue+2];
+ fActiveLimit = fData[opValue+3];
+ U_ASSERT(fActiveStart >= 0);
+ U_ASSERT(fActiveLimit <= fInputLength);
fp->fPatIdx = continueLoc;
break;
}
@@ -5475,7 +5475,7 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
case URX_LBN_END:
// End of a negative look-behind block, after a successful match.
{
- U_ASSERT(opValue>=0 && opValue+4<fPattern->fDataSize);
+ U_ASSERT(opValue>=0 && opValue+4<fPattern->fDataSize);
if (fp->fInputIdx != fActiveLimit) {
// The look-behind expression matched, but the match did not
// extend all the way to the point that we are looking behind from.
@@ -5492,10 +5492,10 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
// Restore the orignal input string length, which had been truncated
// inorder to pin the end of the lookbehind match
// to the position being looked-behind.
- fActiveStart = fData[opValue+2];
- fActiveLimit = fData[opValue+3];
- U_ASSERT(fActiveStart >= 0);
- U_ASSERT(fActiveLimit <= fInputLength);
+ fActiveStart = fData[opValue+2];
+ fActiveLimit = fData[opValue+3];
+ U_ASSERT(fActiveStart >= 0);
+ U_ASSERT(fActiveLimit <= fInputLength);
// Restore original stack position, discarding any state saved
// by the successful pattern match.
@@ -5517,9 +5517,9 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
// This op scans through all matching input.
// The following LOOP_C op emulates stack unwinding if the following pattern fails.
{
- U_ASSERT(opValue > 0 && opValue < fSets->size());
+ U_ASSERT(opValue > 0 && opValue < fSets->size());
Regex8BitSet *s8 = &fPattern->fSets8[opValue];
- UnicodeSet *s = (UnicodeSet *)fSets->elementAt(opValue);
+ UnicodeSet *s = (UnicodeSet *)fSets->elementAt(opValue);
// Loop through input, until either the input is exhausted or
// we reach a character that is not a member of the set.
@@ -5672,7 +5672,7 @@ void RegexMatcher::MatchChunkAt(int32_t startIdx, UBool toEnd, UErrorCode &statu
default:
// Trouble. The compiled pattern contains an entry with an
// unrecognized type tag.
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
if (U_FAILURE(status)) {
@@ -5712,4 +5712,4 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RegexMatcher)
U_NAMESPACE_END
#endif // !UCONFIG_NO_REGULAR_EXPRESSIONS
-
+
diff --git a/contrib/libs/icu/i18n/remtrans.cpp b/contrib/libs/icu/i18n/remtrans.cpp
index 03b878575c..8c754c8738 100644
--- a/contrib/libs/icu/i18n/remtrans.cpp
+++ b/contrib/libs/icu/i18n/remtrans.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -48,10 +48,10 @@ RemoveTransliterator::RemoveTransliterator() : Transliterator(UnicodeString(TRUE
RemoveTransliterator::~RemoveTransliterator() {}
-RemoveTransliterator* RemoveTransliterator::clone() const {
- RemoveTransliterator* result = new RemoveTransliterator();
+RemoveTransliterator* RemoveTransliterator::clone() const {
+ RemoveTransliterator* result = new RemoveTransliterator();
if (result != NULL && getFilter() != 0) {
- result->adoptFilter(getFilter()->clone());
+ result->adoptFilter(getFilter()->clone());
}
return result;
}
diff --git a/contrib/libs/icu/i18n/remtrans.h b/contrib/libs/icu/i18n/remtrans.h
index 13de01594a..511804172d 100644
--- a/contrib/libs/icu/i18n/remtrans.h
+++ b/contrib/libs/icu/i18n/remtrans.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -47,7 +47,7 @@ public:
* Transliterator API.
* @return A copy of the object.
*/
- virtual RemoveTransliterator* clone() const;
+ virtual RemoveTransliterator* clone() const;
/**
* Implements {@link Transliterator#handleTransliterate}.
diff --git a/contrib/libs/icu/i18n/repattrn.cpp b/contrib/libs/icu/i18n/repattrn.cpp
index b3028e04f7..cce5dd654e 100644
--- a/contrib/libs/icu/i18n/repattrn.cpp
+++ b/contrib/libs/icu/i18n/repattrn.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
//
// file: repattrn.cpp
@@ -136,20 +136,20 @@ RegexPattern &RegexPattern::operator = (const RegexPattern &other) {
}
// Copy the named capture group hash map.
- if (other.fNamedCaptureMap != nullptr && initNamedCaptureMap()) {
- int32_t hashPos = UHASH_FIRST;
- while (const UHashElement *hashEl = uhash_nextElement(other.fNamedCaptureMap, &hashPos)) {
- if (U_FAILURE(fDeferredStatus)) {
- break;
- }
- const UnicodeString *name = (const UnicodeString *)hashEl->key.pointer;
- UnicodeString *key = new UnicodeString(*name);
- int32_t val = hashEl->value.integer;
- if (key == NULL) {
- fDeferredStatus = U_MEMORY_ALLOCATION_ERROR;
- } else {
- uhash_puti(fNamedCaptureMap, key, val, &fDeferredStatus);
- }
+ if (other.fNamedCaptureMap != nullptr && initNamedCaptureMap()) {
+ int32_t hashPos = UHASH_FIRST;
+ while (const UHashElement *hashEl = uhash_nextElement(other.fNamedCaptureMap, &hashPos)) {
+ if (U_FAILURE(fDeferredStatus)) {
+ break;
+ }
+ const UnicodeString *name = (const UnicodeString *)hashEl->key.pointer;
+ UnicodeString *key = new UnicodeString(*name);
+ int32_t val = hashEl->value.integer;
+ if (key == NULL) {
+ fDeferredStatus = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ uhash_puti(fNamedCaptureMap, key, val, &fDeferredStatus);
+ }
}
}
return *this;
@@ -193,32 +193,32 @@ void RegexPattern::init() {
return;
}
if (fCompiledPat == NULL || fGroupMap == NULL || fSets == NULL ||
- fInitialChars == NULL || fInitialChars8 == NULL) {
+ fInitialChars == NULL || fInitialChars8 == NULL) {
fDeferredStatus = U_MEMORY_ALLOCATION_ERROR;
return;
}
// Slot zero of the vector of sets is reserved. Fill it here.
fSets->addElement((int32_t)0, fDeferredStatus);
-}
-
-
-bool RegexPattern::initNamedCaptureMap() {
- if (fNamedCaptureMap) {
- return true;
- }
- fNamedCaptureMap = uhash_openSize(uhash_hashUnicodeString, // Key hash function
- uhash_compareUnicodeString, // Key comparator function
- uhash_compareLong, // Value comparator function
- 7, // Initial table capacity
- &fDeferredStatus);
- if (U_FAILURE(fDeferredStatus)) {
- return false;
- }
-
+}
+
+
+bool RegexPattern::initNamedCaptureMap() {
+ if (fNamedCaptureMap) {
+ return true;
+ }
+ fNamedCaptureMap = uhash_openSize(uhash_hashUnicodeString, // Key hash function
+ uhash_compareUnicodeString, // Key comparator function
+ uhash_compareLong, // Value comparator function
+ 7, // Initial table capacity
+ &fDeferredStatus);
+ if (U_FAILURE(fDeferredStatus)) {
+ return false;
+ }
+
// fNamedCaptureMap owns its key strings, type (UnicodeString *)
uhash_setKeyDeleter(fNamedCaptureMap, uprv_deleteUObject);
- return true;
+ return true;
}
//--------------------------------------------------------------------------
@@ -255,10 +255,10 @@ void RegexPattern::zap() {
delete fPatternString;
fPatternString = NULL;
}
- if (fNamedCaptureMap != NULL) {
- uhash_close(fNamedCaptureMap);
- fNamedCaptureMap = NULL;
- }
+ if (fNamedCaptureMap != NULL) {
+ uhash_close(fNamedCaptureMap);
+ fNamedCaptureMap = NULL;
+ }
}
@@ -629,7 +629,7 @@ int32_t RegexPattern::groupNumberFromName(const UnicodeString &groupName, UError
// No need to explicitly check for syntactically valid names.
// Invalid ones will never be in the map, and the lookup will fail.
- int32_t number = fNamedCaptureMap ? uhash_geti(fNamedCaptureMap, &groupName) : 0;
+ int32_t number = fNamedCaptureMap ? uhash_geti(fNamedCaptureMap, &groupName) : 0;
if (number == 0) {
status = U_REGEX_INVALID_CAPTURE_GROUP_NAME;
}
@@ -657,7 +657,7 @@ int32_t RegexPattern::split(const UnicodeString &input,
{
if (U_FAILURE(status)) {
return 0;
- }
+ }
RegexMatcher m(this);
int32_t r = 0;
@@ -678,7 +678,7 @@ int32_t RegexPattern::split(UText *input,
{
if (U_FAILURE(status)) {
return 0;
- }
+ }
RegexMatcher m(this);
int32_t r = 0;
@@ -801,8 +801,8 @@ void RegexPattern::dumpOp(int32_t index) const {
printf("NOT ");
val &= ~URX_NEG_SET;
}
- UnicodeSet &set = RegexStaticSets::gStaticSets->fPropSets[val];
- set.toPattern(s, TRUE);
+ UnicodeSet &set = RegexStaticSets::gStaticSets->fPropSets[val];
+ set.toPattern(s, TRUE);
printf("%s", CStr(s)());
}
break;
@@ -846,7 +846,7 @@ void RegexPattern::dumpPattern() const {
}
printf("Named Capture Groups:\n");
- if (!fNamedCaptureMap || uhash_count(fNamedCaptureMap) == 0) {
+ if (!fNamedCaptureMap || uhash_count(fNamedCaptureMap) == 0) {
printf(" None\n");
} else {
int32_t pos = UHASH_FIRST;
diff --git a/contrib/libs/icu/i18n/rulebasedcollator.cpp b/contrib/libs/icu/i18n/rulebasedcollator.cpp
index 60acf17815..23f9622c2d 100644
--- a/contrib/libs/icu/i18n/rulebasedcollator.cpp
+++ b/contrib/libs/icu/i18n/rulebasedcollator.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -220,7 +220,7 @@ RuleBasedCollator::adoptTailoring(CollationTailoring *t, UErrorCode &errorCode)
actualLocaleIsSameAsValid = FALSE;
}
-RuleBasedCollator *
+RuleBasedCollator *
RuleBasedCollator::clone() const {
return new RuleBasedCollator(*this);
}
@@ -764,9 +764,9 @@ RuleBasedCollator::internalCompareUTF8(const char *left, int32_t leftLength,
// Make sure both or neither strings have a known length.
// We do not optimize for mixed length/termination.
if(leftLength >= 0) {
- if(rightLength < 0) { rightLength = static_cast<int32_t>(uprv_strlen(right)); }
+ if(rightLength < 0) { rightLength = static_cast<int32_t>(uprv_strlen(right)); }
} else {
- if(rightLength >= 0) { leftLength = static_cast<int32_t>(uprv_strlen(left)); }
+ if(rightLength >= 0) { leftLength = static_cast<int32_t>(uprv_strlen(left)); }
}
return doCompare(reinterpret_cast<const uint8_t *>(left), leftLength,
reinterpret_cast<const uint8_t *>(right), rightLength, errorCode);
@@ -862,9 +862,9 @@ public:
} else {
str.setTo(text, (int32_t)(spanLimit - text));
{
- ReorderingBuffer r_buffer(nfcImpl, str);
- if(r_buffer.init(str.length(), errorCode)) {
- nfcImpl.makeFCD(spanLimit, textLimit, &r_buffer, errorCode);
+ ReorderingBuffer r_buffer(nfcImpl, str);
+ if(r_buffer.init(str.length(), errorCode)) {
+ nfcImpl.makeFCD(spanLimit, textLimit, &r_buffer, errorCode);
}
}
if(U_SUCCESS(errorCode)) {
@@ -1554,7 +1554,7 @@ RuleBasedCollator::internalGetShortDefinitionString(const char *locale,
"collation", locale,
NULL, &errorCode);
if(U_FAILURE(errorCode)) { return 0; }
- resultLocale[length] = 0;
+ resultLocale[length] = 0;
// Append items in alphabetic order of their short definition letters.
CharString result;
@@ -1581,11 +1581,11 @@ RuleBasedCollator::internalGetShortDefinitionString(const char *locale,
length = uloc_getKeywordValue(resultLocale, "collation", subtag, UPRV_LENGTHOF(subtag), &errorCode);
appendSubtag(result, 'K', subtag, length, errorCode);
length = uloc_getLanguage(resultLocale, subtag, UPRV_LENGTHOF(subtag), &errorCode);
- if (length == 0) {
- appendSubtag(result, 'L', "root", 4, errorCode);
- } else {
- appendSubtag(result, 'L', subtag, length, errorCode);
- }
+ if (length == 0) {
+ appendSubtag(result, 'L', "root", 4, errorCode);
+ } else {
+ appendSubtag(result, 'L', subtag, length, errorCode);
+ }
if(attributeHasBeenSetExplicitly(UCOL_NORMALIZATION_MODE)) {
appendAttribute(result, 'N', getAttribute(UCOL_NORMALIZATION_MODE, errorCode), errorCode);
}
diff --git a/contrib/libs/icu/i18n/scientificnumberformatter.cpp b/contrib/libs/icu/i18n/scientificnumberformatter.cpp
index 6c2cb3aeed..a54dcb17f1 100644
--- a/contrib/libs/icu/i18n/scientificnumberformatter.cpp
+++ b/contrib/libs/icu/i18n/scientificnumberformatter.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -16,7 +16,7 @@
#include "unicode/utf16.h"
#include "unicode/uniset.h"
#include "unicode/decimfmt.h"
-#include "static_unicode_sets.h"
+#include "static_unicode_sets.h"
U_NAMESPACE_BEGIN
@@ -121,7 +121,7 @@ ScientificNumberFormatter *ScientificNumberFormatter::createInstance(
return result;
}
-ScientificNumberFormatter::SuperscriptStyle *ScientificNumberFormatter::SuperscriptStyle::clone() const {
+ScientificNumberFormatter::SuperscriptStyle *ScientificNumberFormatter::SuperscriptStyle::clone() const {
return new ScientificNumberFormatter::SuperscriptStyle(*this);
}
@@ -148,17 +148,17 @@ UnicodeString &ScientificNumberFormatter::SuperscriptStyle::format(
break;
case UNUM_EXPONENT_SIGN_FIELD:
{
- using namespace icu::numparse::impl;
+ using namespace icu::numparse::impl;
int32_t beginIndex = fp.getBeginIndex();
int32_t endIndex = fp.getEndIndex();
UChar32 aChar = original.char32At(beginIndex);
- if (unisets::get(unisets::MINUS_SIGN)->contains(aChar)) {
+ if (unisets::get(unisets::MINUS_SIGN)->contains(aChar)) {
appendTo.append(
original,
copyFromOffset,
beginIndex - copyFromOffset);
appendTo.append(kSuperscriptMinusSign);
- } else if (unisets::get(unisets::PLUS_SIGN)->contains(aChar)) {
+ } else if (unisets::get(unisets::PLUS_SIGN)->contains(aChar)) {
appendTo.append(
original,
copyFromOffset,
@@ -195,7 +195,7 @@ UnicodeString &ScientificNumberFormatter::SuperscriptStyle::format(
return appendTo;
}
-ScientificNumberFormatter::MarkupStyle *ScientificNumberFormatter::MarkupStyle::clone() const {
+ScientificNumberFormatter::MarkupStyle *ScientificNumberFormatter::MarkupStyle::clone() const {
return new ScientificNumberFormatter::MarkupStyle(*this);
}
@@ -242,7 +242,7 @@ ScientificNumberFormatter::ScientificNumberFormatter(
DecimalFormat *fmtToAdopt, Style *styleToAdopt, UErrorCode &status)
: fPreExponent(),
fDecimalFormat(fmtToAdopt),
- fStyle(styleToAdopt) {
+ fStyle(styleToAdopt) {
if (U_FAILURE(status)) {
return;
}
@@ -263,7 +263,7 @@ ScientificNumberFormatter::ScientificNumberFormatter(
: UObject(other),
fPreExponent(other.fPreExponent),
fDecimalFormat(NULL),
- fStyle(NULL) {
+ fStyle(NULL) {
fDecimalFormat = static_cast<DecimalFormat *>(
other.fDecimalFormat->clone());
fStyle = other.fStyle->clone();
diff --git a/contrib/libs/icu/i18n/scriptset.cpp b/contrib/libs/icu/i18n/scriptset.cpp
index 18a3b263b7..86f1563db1 100644
--- a/contrib/libs/icu/i18n/scriptset.cpp
+++ b/contrib/libs/icu/i18n/scriptset.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -29,7 +29,7 @@ U_NAMESPACE_BEGIN
//
//----------------------------------------------------------------------------
ScriptSet::ScriptSet() {
- uprv_memset(bits, 0, sizeof(bits));
+ uprv_memset(bits, 0, sizeof(bits));
}
ScriptSet::~ScriptSet() {
@@ -40,7 +40,7 @@ ScriptSet::ScriptSet(const ScriptSet &other) {
}
ScriptSet & ScriptSet::operator =(const ScriptSet &other) {
- uprv_memcpy(bits, other.bits, sizeof(bits));
+ uprv_memcpy(bits, other.bits, sizeof(bits));
return *this;
}
@@ -57,7 +57,7 @@ UBool ScriptSet::test(UScriptCode script, UErrorCode &status) const {
if (U_FAILURE(status)) {
return FALSE;
}
- if (script < 0 || (int32_t)script >= SCRIPT_LIMIT) {
+ if (script < 0 || (int32_t)script >= SCRIPT_LIMIT) {
status = U_ILLEGAL_ARGUMENT_ERROR;
return FALSE;
}
@@ -71,7 +71,7 @@ ScriptSet &ScriptSet::set(UScriptCode script, UErrorCode &status) {
if (U_FAILURE(status)) {
return *this;
}
- if (script < 0 || (int32_t)script >= SCRIPT_LIMIT) {
+ if (script < 0 || (int32_t)script >= SCRIPT_LIMIT) {
status = U_ILLEGAL_ARGUMENT_ERROR;
return *this;
}
@@ -85,7 +85,7 @@ ScriptSet &ScriptSet::reset(UScriptCode script, UErrorCode &status) {
if (U_FAILURE(status)) {
return *this;
}
- if (script < 0 || (int32_t)script >= SCRIPT_LIMIT) {
+ if (script < 0 || (int32_t)script >= SCRIPT_LIMIT) {
status = U_ILLEGAL_ARGUMENT_ERROR;
return *this;
}
@@ -119,7 +119,7 @@ ScriptSet &ScriptSet::intersect(UScriptCode script, UErrorCode &status) {
}
return *this;
}
-
+
UBool ScriptSet::intersects(const ScriptSet &other) const {
for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
if ((bits[i] & other.bits[i]) != 0) {
@@ -145,7 +145,7 @@ ScriptSet &ScriptSet::setAll() {
ScriptSet &ScriptSet::resetAll() {
- uprv_memset(bits, 0, sizeof(bits));
+ uprv_memset(bits, 0, sizeof(bits));
return *this;
}
@@ -177,7 +177,7 @@ int32_t ScriptSet::nextSetBit(int32_t fromIndex) const {
return -1;
}
UErrorCode status = U_ZERO_ERROR;
- for (int32_t scriptIndex = fromIndex; scriptIndex < SCRIPT_LIMIT; scriptIndex++) {
+ for (int32_t scriptIndex = fromIndex; scriptIndex < SCRIPT_LIMIT; scriptIndex++) {
if (test((UScriptCode)scriptIndex, status)) {
return scriptIndex;
}
@@ -243,14 +243,14 @@ ScriptSet &ScriptSet::parseScripts(const UnicodeString &scriptString, UErrorCode
void ScriptSet::setScriptExtensions(UChar32 codePoint, UErrorCode& status) {
if (U_FAILURE(status)) { return; }
- static const int32_t FIRST_GUESS_SCRIPT_CAPACITY = 20;
+ static const int32_t FIRST_GUESS_SCRIPT_CAPACITY = 20;
MaybeStackArray<UScriptCode,FIRST_GUESS_SCRIPT_CAPACITY> scripts;
UErrorCode internalStatus = U_ZERO_ERROR;
int32_t script_count = -1;
while (TRUE) {
script_count = uscript_getScriptExtensions(
- codePoint, scripts.getAlias(), scripts.getCapacity(), &internalStatus);
+ codePoint, scripts.getAlias(), scripts.getCapacity(), &internalStatus);
if (internalStatus == U_BUFFER_OVERFLOW_ERROR) {
// Need to allocate more space
if (scripts.resize(script_count) == NULL) {
@@ -290,7 +290,7 @@ uhash_compareScriptSet(UElement key0, UElement key1) {
icu::ScriptSet *s0 = static_cast<icu::ScriptSet *>(key0.pointer);
icu::ScriptSet *s1 = static_cast<icu::ScriptSet *>(key1.pointer);
int32_t diff = s0->countMembers() - s1->countMembers();
- if (diff != 0) return static_cast<UBool>(diff);
+ if (diff != 0) return static_cast<UBool>(diff);
int32_t i0 = s0->nextSetBit(0);
int32_t i1 = s1->nextSetBit(0);
while ((diff = i0-i1) == 0 && i0 > 0) {
diff --git a/contrib/libs/icu/i18n/scriptset.h b/contrib/libs/icu/i18n/scriptset.h
index a41ab737a6..55019ff7e7 100644
--- a/contrib/libs/icu/i18n/scriptset.h
+++ b/contrib/libs/icu/i18n/scriptset.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -35,14 +35,14 @@ U_NAMESPACE_BEGIN
//-------------------------------------------------------------------------------
class U_I18N_API ScriptSet: public UMemory {
public:
- static constexpr int32_t SCRIPT_LIMIT = 224; // multiple of 32!
-
+ static constexpr int32_t SCRIPT_LIMIT = 224; // multiple of 32!
+
ScriptSet();
ScriptSet(const ScriptSet &other);
~ScriptSet();
UBool operator == (const ScriptSet &other) const;
- UBool operator != (const ScriptSet &other) const {return !(*this == other);}
+ UBool operator != (const ScriptSet &other) const {return !(*this == other);}
ScriptSet & operator = (const ScriptSet &other);
UBool test(UScriptCode script, UErrorCode &status) const;
@@ -69,7 +69,7 @@ class U_I18N_API ScriptSet: public UMemory {
void setScriptExtensions(UChar32 codePoint, UErrorCode& status);
private:
- uint32_t bits[SCRIPT_LIMIT / 32];
+ uint32_t bits[SCRIPT_LIMIT / 32];
};
U_NAMESPACE_END
diff --git a/contrib/libs/icu/i18n/search.cpp b/contrib/libs/icu/i18n/search.cpp
index f944b68455..9da3509adb 100644
--- a/contrib/libs/icu/i18n/search.cpp
+++ b/contrib/libs/icu/i18n/search.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
diff --git a/contrib/libs/icu/i18n/selfmt.cpp b/contrib/libs/icu/i18n/selfmt.cpp
index 47e53d75de..19c6ec6c06 100644
--- a/contrib/libs/icu/i18n/selfmt.cpp
+++ b/contrib/libs/icu/i18n/selfmt.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/********************************************************************
* COPYRIGHT:
@@ -151,7 +151,7 @@ int32_t SelectFormat::findSubMessage(const MessagePattern& pattern, int32_t part
return msgStart;
}
-SelectFormat* SelectFormat::clone() const
+SelectFormat* SelectFormat::clone() const
{
return new SelectFormat(*this);
}
diff --git a/contrib/libs/icu/i18n/selfmtimpl.h b/contrib/libs/icu/i18n/selfmtimpl.h
index a36d1a5c34..fee4e80adc 100644
--- a/contrib/libs/icu/i18n/selfmtimpl.h
+++ b/contrib/libs/icu/i18n/selfmtimpl.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/********************************************************************
* COPYRIGHT:
diff --git a/contrib/libs/icu/i18n/sharedbreakiterator.cpp b/contrib/libs/icu/i18n/sharedbreakiterator.cpp
index 82f482bdd7..e9d470218b 100644
--- a/contrib/libs/icu/i18n/sharedbreakiterator.cpp
+++ b/contrib/libs/icu/i18n/sharedbreakiterator.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/sharedbreakiterator.h b/contrib/libs/icu/i18n/sharedbreakiterator.h
index b6d67bc8e8..1911da82d2 100644
--- a/contrib/libs/icu/i18n/sharedbreakiterator.h
+++ b/contrib/libs/icu/i18n/sharedbreakiterator.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
diff --git a/contrib/libs/icu/i18n/sharedcalendar.h b/contrib/libs/icu/i18n/sharedcalendar.h
index 1526f92e88..c0edb57dbf 100644
--- a/contrib/libs/icu/i18n/sharedcalendar.h
+++ b/contrib/libs/icu/i18n/sharedcalendar.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
diff --git a/contrib/libs/icu/i18n/shareddateformatsymbols.h b/contrib/libs/icu/i18n/shareddateformatsymbols.h
index 66a06ecae5..9d314f46ea 100644
--- a/contrib/libs/icu/i18n/shareddateformatsymbols.h
+++ b/contrib/libs/icu/i18n/shareddateformatsymbols.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
@@ -12,9 +12,9 @@
#define __SHARED_DATEFORMATSYMBOLS_H__
#include "unicode/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-
+
+#if !UCONFIG_NO_FORMATTING
+
#include "sharedobject.h"
#include "unicode/dtfmtsym.h"
@@ -36,6 +36,6 @@ private:
U_NAMESPACE_END
-#endif /* !UCONFIG_NO_FORMATTING */
-
+#endif /* !UCONFIG_NO_FORMATTING */
+
#endif
diff --git a/contrib/libs/icu/i18n/sharednumberformat.h b/contrib/libs/icu/i18n/sharednumberformat.h
index a7e105b5ac..7cc41a3320 100644
--- a/contrib/libs/icu/i18n/sharednumberformat.h
+++ b/contrib/libs/icu/i18n/sharednumberformat.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
diff --git a/contrib/libs/icu/i18n/sharedpluralrules.h b/contrib/libs/icu/i18n/sharedpluralrules.h
index 28d8b25c14..cdfd112be3 100644
--- a/contrib/libs/icu/i18n/sharedpluralrules.h
+++ b/contrib/libs/icu/i18n/sharedpluralrules.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
diff --git a/contrib/libs/icu/i18n/simpletz.cpp b/contrib/libs/icu/i18n/simpletz.cpp
index 7972e2bb04..277a70e583 100644
--- a/contrib/libs/icu/i18n/simpletz.cpp
+++ b/contrib/libs/icu/i18n/simpletz.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -33,7 +33,7 @@
#include "unicode/gregocal.h"
#include "unicode/smpdtfmt.h"
-#include "cmemory.h"
+#include "cmemory.h"
#include "gregoimp.h"
#include "umutex.h"
@@ -178,7 +178,7 @@ void SimpleTimeZone::construct(int32_t rawOffsetGMT,
decodeRules(status);
- if (savingsDST == 0) {
+ if (savingsDST == 0) {
status = U_ILLEGAL_ARGUMENT_ERROR;
}
}
@@ -243,7 +243,7 @@ SimpleTimeZone::operator==(const TimeZone& that) const
// -------------------------------------
// Called by TimeZone::createDefault() inside a Mutex - be careful.
-SimpleTimeZone*
+SimpleTimeZone*
SimpleTimeZone::clone() const
{
return new SimpleTimeZone(*this);
@@ -687,7 +687,7 @@ SimpleTimeZone::setRawOffset(int32_t offsetMillis)
void
SimpleTimeZone::setDSTSavings(int32_t millisSavedDuringDST, UErrorCode& status)
{
- if (millisSavedDuringDST == 0) {
+ if (millisSavedDuringDST == 0) {
status = U_ILLEGAL_ARGUMENT_ERROR;
}
else {
@@ -1084,7 +1084,7 @@ SimpleTimeZone::checkTransitionRules(UErrorCode& status) const {
if (U_FAILURE(status)) {
return;
}
- static UMutex gLock;
+ static UMutex gLock;
umtx_lock(&gLock);
if (!transitionRulesInitialized) {
SimpleTimeZone *ncThis = const_cast<SimpleTimeZone*>(this);
@@ -1190,22 +1190,22 @@ SimpleTimeZone::initTransitionRules(UErrorCode& status) {
// Create a TimeZoneRule for initial time
if (firstStdStart < firstDstStart) {
initialRule = new InitialTimeZoneRule(tzid+UnicodeString(DST_STR), getRawOffset(), dstRule->getDSTSavings());
- if (initialRule == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- deleteTransitionRules();
- return;
- }
+ if (initialRule == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
+ }
firstTransition = new TimeZoneTransition(firstStdStart, *initialRule, *stdRule);
} else {
initialRule = new InitialTimeZoneRule(tzid+UnicodeString(STD_STR), getRawOffset(), 0);
- if (initialRule == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- deleteTransitionRules();
- return;
- }
+ if (initialRule == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
+ }
firstTransition = new TimeZoneTransition(firstDstStart, *initialRule, *dstRule);
}
- if (firstTransition == NULL) {
+ if (firstTransition == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
deleteTransitionRules();
return;
diff --git a/contrib/libs/icu/i18n/smpdtfmt.cpp b/contrib/libs/icu/i18n/smpdtfmt.cpp
index d704642b05..7f5d4777a6 100644
--- a/contrib/libs/icu/i18n/smpdtfmt.cpp
+++ b/contrib/libs/icu/i18n/smpdtfmt.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -48,12 +48,12 @@
#include "unicode/simpletz.h"
#include "unicode/rbtz.h"
#include "unicode/tzfmt.h"
-#include "unicode/ucasemap.h"
+#include "unicode/ucasemap.h"
#include "unicode/utf16.h"
#include "unicode/vtzone.h"
#include "unicode/udisplaycontext.h"
#include "unicode/brkiter.h"
-#include "unicode/rbnf.h"
+#include "unicode/rbnf.h"
#include "uresimp.h"
#include "olsontz.h"
#include "patternprops.h"
@@ -66,14 +66,14 @@
#include <float.h>
#include "smpdtfst.h"
#include "sharednumberformat.h"
-#include "ucasemap_imp.h"
+#include "ucasemap_imp.h"
#include "ustr_imp.h"
#include "charstr.h"
#include "uvector.h"
#include "cstr.h"
#include "dayperiodrules.h"
-#include "tznames_impl.h" // ZONE_NAME_U16_MAX
-#include "number_utypes.h"
+#include "tznames_impl.h" // ZONE_NAME_U16_MAX
+#include "number_utypes.h"
#if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
#include <stdio.h>
@@ -230,7 +230,7 @@ static const int32_t gFieldRangeBias[] = {
static const int32_t HEBREW_CAL_CUR_MILLENIUM_START_YEAR = 5000;
static const int32_t HEBREW_CAL_CUR_MILLENIUM_END_YEAR = 6000;
-static UMutex LOCK;
+static UMutex LOCK;
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleDateFormat)
@@ -244,9 +244,9 @@ SimpleDateFormat::NSOverride::~NSOverride() {
void SimpleDateFormat::NSOverride::free() {
NSOverride *cur = this;
while (cur) {
- NSOverride *next_temp = cur->next;
+ NSOverride *next_temp = cur->next;
delete cur;
- cur = next_temp;
+ cur = next_temp;
}
}
@@ -325,7 +325,7 @@ SimpleDateFormat::~SimpleDateFormat()
if (fTimeZoneFormat) {
delete fTimeZoneFormat;
}
- freeFastNumberFormatters();
+ freeFastNumberFormatters();
#if !UCONFIG_NO_BREAK_ITERATION
delete fCapitalizationBrkIter;
@@ -583,14 +583,14 @@ SimpleDateFormat& SimpleDateFormat::operator=(const SimpleDateFormat& other)
fHasMinute = other.fHasMinute;
fHasSecond = other.fHasSecond;
- fLocale = other.fLocale;
-
- // TimeZoneFormat can now be set independently via setter.
- // If it is NULL, it will be lazily initialized from locale
- delete fTimeZoneFormat;
- fTimeZoneFormat = NULL;
- if (other.fTimeZoneFormat) {
- fTimeZoneFormat = new TimeZoneFormat(*other.fTimeZoneFormat);
+ fLocale = other.fLocale;
+
+ // TimeZoneFormat can now be set independently via setter.
+ // If it is NULL, it will be lazily initialized from locale
+ delete fTimeZoneFormat;
+ fTimeZoneFormat = NULL;
+ if (other.fTimeZoneFormat) {
+ fTimeZoneFormat = new TimeZoneFormat(*other.fTimeZoneFormat);
}
#if !UCONFIG_NO_BREAK_ITERATION
@@ -614,16 +614,16 @@ SimpleDateFormat& SimpleDateFormat::operator=(const SimpleDateFormat& other)
}
}
- UErrorCode localStatus = U_ZERO_ERROR;
- freeFastNumberFormatters();
- initFastNumberFormatters(localStatus);
-
+ UErrorCode localStatus = U_ZERO_ERROR;
+ freeFastNumberFormatters();
+ initFastNumberFormatters(localStatus);
+
return *this;
}
//----------------------------------------------------------------------
-SimpleDateFormat*
+SimpleDateFormat*
SimpleDateFormat::clone() const
{
return new SimpleDateFormat(*this);
@@ -859,17 +859,17 @@ SimpleDateFormat::initialize(const Locale& locale,
{
if (U_FAILURE(status)) return;
- parsePattern(); // Need this before initNumberFormatters(), to set fHasHanYearChar
-
- // Simple-minded hack to force Gannen year numbering for ja@calendar=japanese
- // if format is non-numeric (includes 年) and fDateOverride is not already specified.
- // Now this does get updated if applyPattern subsequently changes the pattern type.
- if (fDateOverride.isBogus() && fHasHanYearChar &&
- fCalendar != nullptr && uprv_strcmp(fCalendar->getType(),"japanese") == 0 &&
- uprv_strcmp(fLocale.getLanguage(),"ja") == 0) {
- fDateOverride.setTo(u"y=jpanyear", -1);
- }
-
+ parsePattern(); // Need this before initNumberFormatters(), to set fHasHanYearChar
+
+ // Simple-minded hack to force Gannen year numbering for ja@calendar=japanese
+ // if format is non-numeric (includes 年) and fDateOverride is not already specified.
+ // Now this does get updated if applyPattern subsequently changes the pattern type.
+ if (fDateOverride.isBogus() && fHasHanYearChar &&
+ fCalendar != nullptr && uprv_strcmp(fCalendar->getType(),"japanese") == 0 &&
+ uprv_strcmp(fLocale.getLanguage(),"ja") == 0) {
+ fDateOverride.setTo(u"y=jpanyear", -1);
+ }
+
// We don't need to check that the row count is >= 1, since all 2d arrays have at
// least one row
fNumberFormat = NumberFormat::createInstance(locale, status);
@@ -878,8 +878,8 @@ SimpleDateFormat::initialize(const Locale& locale,
fixNumberFormatForDates(*fNumberFormat);
//fNumberFormat->setLenient(TRUE); // Java uses a custom DateNumberFormat to format/parse
- initNumberFormatters(locale, status);
- initFastNumberFormatters(status);
+ initNumberFormatters(locale, status);
+ initFastNumberFormatters(status);
}
else if (U_SUCCESS(status))
@@ -999,8 +999,8 @@ 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++,
- prevCh, handler, *workCal, status);
+ subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++,
+ prevCh, handler, *workCal, status);
count = 0;
}
if (ch == QUOTE) {
@@ -1027,8 +1027,8 @@ SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo,
// Format the last item in the pattern, if any
if (count > 0) {
- subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++,
- prevCh, handler, *workCal, status);
+ subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++,
+ prevCh, handler, *workCal, status);
}
if (calClone != NULL) {
@@ -1223,47 +1223,47 @@ _appendSymbolWithMonthPattern(UnicodeString& dst, int32_t value, const UnicodeSt
}
//----------------------------------------------------------------------
-
-static number::LocalizedNumberFormatter*
-createFastFormatter(const DecimalFormat* df, int32_t minInt, int32_t maxInt, UErrorCode& status) {
- const number::LocalizedNumberFormatter* lnfBase = df->toNumberFormatter(status);
- if (U_FAILURE(status)) {
- return nullptr;
- }
- return lnfBase->integerWidth(
- number::IntegerWidth::zeroFillTo(minInt).truncateAt(maxInt)
- ).clone().orphan();
-}
-
-void SimpleDateFormat::initFastNumberFormatters(UErrorCode& status) {
- if (U_FAILURE(status)) {
- return;
- }
- auto* df = dynamic_cast<const DecimalFormat*>(fNumberFormat);
- if (df == nullptr) {
- return;
- }
- fFastNumberFormatters[SMPDTFMT_NF_1x10] = createFastFormatter(df, 1, 10, status);
- fFastNumberFormatters[SMPDTFMT_NF_2x10] = createFastFormatter(df, 2, 10, status);
- fFastNumberFormatters[SMPDTFMT_NF_3x10] = createFastFormatter(df, 3, 10, status);
- fFastNumberFormatters[SMPDTFMT_NF_4x10] = createFastFormatter(df, 4, 10, status);
- fFastNumberFormatters[SMPDTFMT_NF_2x2] = createFastFormatter(df, 2, 2, status);
-}
-
-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;
-}
-
-
+
+static number::LocalizedNumberFormatter*
+createFastFormatter(const DecimalFormat* df, int32_t minInt, int32_t maxInt, UErrorCode& status) {
+ const number::LocalizedNumberFormatter* lnfBase = df->toNumberFormatter(status);
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ return lnfBase->integerWidth(
+ number::IntegerWidth::zeroFillTo(minInt).truncateAt(maxInt)
+ ).clone().orphan();
+}
+
+void SimpleDateFormat::initFastNumberFormatters(UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ auto* df = dynamic_cast<const DecimalFormat*>(fNumberFormat);
+ if (df == nullptr) {
+ return;
+ }
+ fFastNumberFormatters[SMPDTFMT_NF_1x10] = createFastFormatter(df, 1, 10, status);
+ fFastNumberFormatters[SMPDTFMT_NF_2x10] = createFastFormatter(df, 2, 10, status);
+ fFastNumberFormatters[SMPDTFMT_NF_3x10] = createFastFormatter(df, 3, 10, status);
+ fFastNumberFormatters[SMPDTFMT_NF_4x10] = createFastFormatter(df, 4, 10, status);
+ fFastNumberFormatters[SMPDTFMT_NF_2x2] = createFastFormatter(df, 2, 2, status);
+}
+
+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)) {
@@ -1322,15 +1322,15 @@ SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeStrin
int32_t nsNameHash = nsName.hashCode();
// See if the numbering system is in the override list, if not, then add it.
- NSOverride *curr = overrideList;
+ NSOverride *curr = overrideList;
const SharedNumberFormat *snf = NULL;
UBool found = FALSE;
- while ( curr && !found ) {
- if ( curr->hash == nsNameHash ) {
- snf = curr->snf;
+ while ( curr && !found ) {
+ if ( curr->hash == nsNameHash ) {
+ snf = curr->snf;
found = TRUE;
}
- curr = curr->next;
+ curr = curr->next;
}
if (!found) {
@@ -1407,11 +1407,11 @@ SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeStrin
//---------------------------------------------------------------------
void
SimpleDateFormat::subFormat(UnicodeString &appendTo,
- char16_t ch,
+ char16_t ch,
int32_t count,
UDisplayContext capitalizationContext,
int32_t fieldNum,
- char16_t fieldToOutput,
+ char16_t fieldToOutput,
FieldPositionHandler& handler,
Calendar& cal,
UErrorCode& status) const
@@ -1426,7 +1426,7 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(ch);
const int32_t maxIntCount = 10;
int32_t beginOffset = appendTo.length();
- const NumberFormat *currentNumberFormat;
+ const NumberFormat *currentNumberFormat;
DateFormatSymbols::ECapitalizationContextUsageType capContextUsageType = DateFormatSymbols::kCapContextUsageOther;
UBool isHebrewCalendar = (uprv_strcmp(cal.getType(),"hebrew") == 0);
@@ -1451,9 +1451,9 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
return;
}
- currentNumberFormat = getNumberFormatByIndex(patternCharIndex);
+ currentNumberFormat = getNumberFormatByIndex(patternCharIndex);
if (currentNumberFormat == NULL) {
- status = U_INTERNAL_PROGRAM_ERROR;
+ status = U_INTERNAL_PROGRAM_ERROR;
return;
}
UnicodeString hebr("hebr", 4, US_INV);
@@ -1573,15 +1573,15 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
case UDAT_FRACTIONAL_SECOND_FIELD:
// Fractional seconds left-justify
{
- int32_t minDigits = (count > 3) ? 3 : count;
+ int32_t minDigits = (count > 3) ? 3 : count;
if (count == 1) {
value /= 100;
} else if (count == 2) {
value /= 10;
}
- zeroPaddingNumber(currentNumberFormat, appendTo, value, minDigits, maxIntCount);
+ zeroPaddingNumber(currentNumberFormat, appendTo, value, minDigits, maxIntCount);
if (count > 3) {
- zeroPaddingNumber(currentNumberFormat, appendTo, 0, count - 3, maxIntCount);
+ zeroPaddingNumber(currentNumberFormat, appendTo, 0, count - 3, maxIntCount);
}
}
break;
@@ -1695,109 +1695,109 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
case UDAT_TIMEZONE_ISO_FIELD: // 'X'
case UDAT_TIMEZONE_ISO_LOCAL_FIELD: // 'x'
{
- UChar zsbuf[ZONE_NAME_U16_MAX];
+ UChar zsbuf[ZONE_NAME_U16_MAX];
UnicodeString zoneString(zsbuf, 0, UPRV_LENGTHOF(zsbuf));
const TimeZone& tz = cal.getTimeZone();
UDate date = cal.getTime(status);
- const TimeZoneFormat *tzfmt = tzFormat(status);
+ const TimeZoneFormat *tzfmt = tzFormat(status);
if (U_SUCCESS(status)) {
if (patternCharIndex == UDAT_TIMEZONE_FIELD) {
if (count < 4) {
// "z", "zz", "zzz"
- tzfmt->format(UTZFMT_STYLE_SPECIFIC_SHORT, tz, date, zoneString);
+ tzfmt->format(UTZFMT_STYLE_SPECIFIC_SHORT, tz, date, zoneString);
capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort;
} else {
// "zzzz" or longer
- tzfmt->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"
- tzfmt->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"
- tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString);
+ tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString);
} else {
// "ZZ", "ZZZ", "ZZZZ"
- tzfmt->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"
- tzfmt->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"
- tzfmt->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"
- tzfmt->format(UTZFMT_STYLE_ZONE_ID_SHORT, tz, date, zoneString);
+ tzfmt->format(UTZFMT_STYLE_ZONE_ID_SHORT, tz, date, zoneString);
} else if (count == 2) {
// "VV"
- tzfmt->format(UTZFMT_STYLE_ZONE_ID, tz, date, zoneString);
+ tzfmt->format(UTZFMT_STYLE_ZONE_ID, tz, date, zoneString);
} else if (count == 3) {
// "VVV"
- tzfmt->format(UTZFMT_STYLE_EXEMPLAR_LOCATION, tz, date, zoneString);
+ tzfmt->format(UTZFMT_STYLE_EXEMPLAR_LOCATION, tz, date, zoneString);
} else if (count == 4) {
// "VVVV"
- tzfmt->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"
- tzfmt->format(UTZFMT_STYLE_LOCALIZED_GMT_SHORT, tz, date, zoneString);
+ tzfmt->format(UTZFMT_STYLE_LOCALIZED_GMT_SHORT, tz, date, zoneString);
} else if (count == 4) {
// "OOOO"
- tzfmt->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"
- tzfmt->format(UTZFMT_STYLE_ISO_BASIC_SHORT, tz, date, zoneString);
+ tzfmt->format(UTZFMT_STYLE_ISO_BASIC_SHORT, tz, date, zoneString);
} else if (count == 2) {
// "XX"
- tzfmt->format(UTZFMT_STYLE_ISO_BASIC_FIXED, tz, date, zoneString);
+ tzfmt->format(UTZFMT_STYLE_ISO_BASIC_FIXED, tz, date, zoneString);
} else if (count == 3) {
// "XXX"
- tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_FIXED, tz, date, zoneString);
+ tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_FIXED, tz, date, zoneString);
} else if (count == 4) {
// "XXXX"
- tzfmt->format(UTZFMT_STYLE_ISO_BASIC_FULL, tz, date, zoneString);
+ tzfmt->format(UTZFMT_STYLE_ISO_BASIC_FULL, tz, date, zoneString);
} else if (count == 5) {
// "XXXXX"
- tzfmt->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"
- tzfmt->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"
- tzfmt->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"
- tzfmt->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"
- tzfmt->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"
- tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL, tz, date, zoneString);
+ tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL, tz, date, zoneString);
}
}
else {
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
}
appendTo += zoneString;
@@ -1843,14 +1843,14 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
// Stealing am/pm value to use as our array index.
// It works out: am/midnight are both 0, pm/noon are both 1,
// 12 am is 12 midnight, and 12 pm is 12 noon.
- int32_t val = cal.get(UCAL_AM_PM, status);
+ int32_t val = cal.get(UCAL_AM_PM, status);
if (count <= 3) {
- toAppend = &fSymbols->fAbbreviatedDayPeriods[val];
+ toAppend = &fSymbols->fAbbreviatedDayPeriods[val];
} else if (count == 4 || count > 5) {
- toAppend = &fSymbols->fWideDayPeriods[val];
+ toAppend = &fSymbols->fWideDayPeriods[val];
} else { // count == 5
- toAppend = &fSymbols->fNarrowDayPeriods[val];
+ toAppend = &fSymbols->fNarrowDayPeriods[val];
}
}
@@ -1859,11 +1859,11 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
// In either case, fall back to am/pm.
if (toAppend == NULL || toAppend->isBogus()) {
// Reformat with identical arguments except ch, now changed to 'a'.
- // We are passing a different fieldToOutput because we want to add
- // 'b' to field position. This makes this fallback stable when
- // there is a data change on locales.
- subFormat(appendTo, u'a', count, capitalizationContext, fieldNum, u'b', handler, cal, status);
- return;
+ // We are passing a different fieldToOutput because we want to add
+ // 'b' to field position. This makes this fallback stable when
+ // there is a data change on locales.
+ subFormat(appendTo, u'a', count, capitalizationContext, fieldNum, u'b', handler, cal, status);
+ return;
} else {
appendTo += *toAppend;
}
@@ -1883,11 +1883,11 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
if (ruleSet == NULL) {
// Data doesn't exist for the locale we're looking for.
// Falling back to am/pm.
- // We are passing a different fieldToOutput because we want to add
- // 'B' to field position. This makes this fallback stable when
- // there is a data change on locales.
- subFormat(appendTo, u'a', count, capitalizationContext, fieldNum, u'B', handler, cal, status);
- return;
+ // We are passing a different fieldToOutput because we want to add
+ // 'B' to field position. This makes this fallback stable when
+ // there is a data change on locales.
+ subFormat(appendTo, u'a', count, capitalizationContext, fieldNum, u'B', handler, cal, status);
+ return;
}
// Get current display time.
@@ -1956,11 +1956,11 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
if (periodType == DayPeriodRules::DAYPERIOD_AM ||
periodType == DayPeriodRules::DAYPERIOD_PM ||
toAppend->isBogus()) {
- // We are passing a different fieldToOutput because we want to add
- // 'B' to field position iterator. This makes this fallback stable when
- // there is a data change on locales.
- subFormat(appendTo, u'a', count, capitalizationContext, fieldNum, u'B', handler, cal, status);
- return;
+ // We are passing a different fieldToOutput because we want to add
+ // 'B' to field position iterator. This makes this fallback stable when
+ // there is a data change on locales.
+ subFormat(appendTo, u'a', count, capitalizationContext, fieldNum, u'B', handler, cal, status);
+ return;
}
else {
appendTo += *toAppend;
@@ -1977,8 +1977,8 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
}
#if !UCONFIG_NO_BREAK_ITERATION
// if first field, check to see whether we need to and are able to titlecase it
- if (fieldNum == 0 && fCapitalizationBrkIter != NULL && appendTo.length() > beginOffset &&
- u_islower(appendTo.char32At(beginOffset))) {
+ if (fieldNum == 0 && fCapitalizationBrkIter != NULL && appendTo.length() > beginOffset &&
+ u_islower(appendTo.char32At(beginOffset))) {
UBool titlecase = FALSE;
switch (capitalizationContext) {
case UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE:
@@ -1995,16 +1995,16 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
break;
}
if (titlecase) {
- BreakIterator* const mutableCapitalizationBrkIter = fCapitalizationBrkIter->clone();
+ BreakIterator* const mutableCapitalizationBrkIter = fCapitalizationBrkIter->clone();
UnicodeString firstField(appendTo, beginOffset);
- firstField.toTitle(mutableCapitalizationBrkIter, fLocale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
+ firstField.toTitle(mutableCapitalizationBrkIter, fLocale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
appendTo.replaceBetween(beginOffset, appendTo.length(), firstField);
- delete mutableCapitalizationBrkIter;
+ delete mutableCapitalizationBrkIter;
}
}
#endif
- handler.addAttribute(DateFormatSymbols::getPatternCharIndex(fieldToOutput), beginOffset, appendTo.length());
+ handler.addAttribute(DateFormatSymbols::getPatternCharIndex(fieldToOutput), beginOffset, appendTo.length());
}
//----------------------------------------------------------------------
@@ -2020,11 +2020,11 @@ void SimpleDateFormat::adoptNumberFormat(NumberFormat *formatToAdopt) {
freeSharedNumberFormatters(fSharedNumberFormatters);
fSharedNumberFormatters = NULL;
}
-
- // Also re-compute the fast formatters.
- UErrorCode localStatus = U_ZERO_ERROR;
- freeFastNumberFormatters();
- initFastNumberFormatters(localStatus);
+
+ // Also re-compute the fast formatters.
+ UErrorCode localStatus = U_ZERO_ERROR;
+ freeFastNumberFormatters();
+ initFastNumberFormatters(localStatus);
}
void SimpleDateFormat::adoptNumberFormat(const UnicodeString& fields, NumberFormat *formatToAdopt, UErrorCode &status){
@@ -2076,58 +2076,58 @@ SimpleDateFormat::getNumberFormatForField(UChar field) const {
//----------------------------------------------------------------------
void
SimpleDateFormat::zeroPaddingNumber(
- const NumberFormat *currentNumberFormat,
+ const NumberFormat *currentNumberFormat,
UnicodeString &appendTo,
int32_t value, int32_t minDigits, int32_t maxDigits) const
{
- 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.getStringRef().toTempUnicodeString());
- return;
- }
-
- // Check for RBNF (no clone necessary)
- auto* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(currentNumberFormat);
- if (rbnf != nullptr) {
- FieldPosition pos(FieldPosition::DONT_CARE);
- rbnf->format(value, appendTo, pos); // 3rd arg is there to speed up processing
- return;
- }
-
- // Fall back to slow path (clone and mutate the NumberFormat)
- if (currentNumberFormat != nullptr) {
+ 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.getStringRef().toTempUnicodeString());
+ return;
+ }
+
+ // Check for RBNF (no clone necessary)
+ auto* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(currentNumberFormat);
+ if (rbnf != nullptr) {
FieldPosition pos(FieldPosition::DONT_CARE);
- LocalPointer<NumberFormat> nf(currentNumberFormat->clone());
- nf->setMinimumIntegerDigits(minDigits);
- nf->setMaximumIntegerDigits(maxDigits);
- nf->format(value, appendTo, pos); // 3rd arg is there to speed up processing
+ rbnf->format(value, appendTo, pos); // 3rd arg is there to speed up processing
+ return;
+ }
+
+ // Fall back to slow path (clone and mutate the NumberFormat)
+ if (currentNumberFormat != nullptr) {
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ LocalPointer<NumberFormat> nf(currentNumberFormat->clone());
+ nf->setMinimumIntegerDigits(minDigits);
+ nf->setMaximumIntegerDigits(maxDigits);
+ nf->format(value, appendTo, pos); // 3rd arg is there to speed up processing
}
}
@@ -2287,7 +2287,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
}
pos = subParse(text, pos, ch, count,
- TRUE, FALSE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType);
+ 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.
@@ -2302,7 +2302,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, &dayPeriodInt);
+ FALSE, TRUE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType, &dayPeriodInt);
if (s == -pos-1) {
// era not present, in special cases allow this to continue
@@ -2311,10 +2311,10 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
if (i+1 < fPattern.length()) {
// move to next pattern character
- UChar c = fPattern.charAt(i+1);
+ UChar c = fPattern.charAt(i+1);
// check for whitespace
- if (PatternProps::isWhiteSpace(c)) {
+ if (PatternProps::isWhiteSpace(c)) {
i++;
// Advance over run in pattern
while ((i+1)<fPattern.length() &&
@@ -2920,7 +2920,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,
+ int32_t patLoc, MessageFormat * numericLeapMonthFormatter, UTimeZoneFormatTimeType *tzTimeType,
int32_t *dayPeriod) const
{
Formattable number;
@@ -2930,7 +2930,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);
- const NumberFormat *currentNumberFormat;
+ const NumberFormat *currentNumberFormat;
UnicodeString temp;
UBool gotNumber = FALSE;
@@ -2942,7 +2942,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
return -start;
}
- currentNumberFormat = getNumberFormatByIndex(patternCharIndex);
+ currentNumberFormat = getNumberFormatByIndex(patternCharIndex);
if (currentNumberFormat == NULL) {
return -start;
}
@@ -3116,9 +3116,9 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
// is treated literally: "2250", "-1", "1", "002".
if (fDateOverride.compare(hebr)==0 && value < 1000) {
value += HEBREW_CAL_CUR_MILLENIUM_START_YEAR;
- } else if (text.moveIndex32(start, 2) == pos.getIndex() && !isChineseCalendar
- && u_isdigit(text.char32At(start))
- && u_isdigit(text.char32At(text.moveIndex32(start, 1))))
+ } else if (text.moveIndex32(start, 2) == pos.getIndex() && !isChineseCalendar
+ && u_isdigit(text.char32At(start))
+ && u_isdigit(text.char32At(text.moveIndex32(start, 1))))
{
// only adjust year for patterns less than 3.
if(count < 3) {
@@ -3156,9 +3156,9 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
// Comment is the same as for UDAT_Year_FIELDs - look above
if (fDateOverride.compare(hebr)==0 && value < 1000) {
value += HEBREW_CAL_CUR_MILLENIUM_START_YEAR;
- } else if (text.moveIndex32(start, 2) == pos.getIndex()
- && u_isdigit(text.char32At(start))
- && u_isdigit(text.char32At(text.moveIndex32(start, 1)))
+ } else if (text.moveIndex32(start, 2) == pos.getIndex()
+ && u_isdigit(text.char32At(start))
+ && u_isdigit(text.char32At(text.moveIndex32(start, 1)))
&& fHaveDefaultCentury )
{
int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100;
@@ -3192,8 +3192,8 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
if (!strcmp(cal.getType(),"hebrew")) {
HebrewCalendar *hc = (HebrewCalendar*)&cal;
if (cal.isSet(UCAL_YEAR)) {
- UErrorCode monthStatus = U_ZERO_ERROR;
- if (!hc->isLeapYear(hc->get(UCAL_YEAR, monthStatus)) && value >= 6) {
+ UErrorCode monthStatus = U_ZERO_ERROR;
+ if (!hc->isLeapYear(hc->get(UCAL_YEAR, monthStatus)) && value >= 6) {
cal.set(UCAL_MONTH, value);
} else {
cal.set(UCAL_MONTH, value - 1);
@@ -3264,7 +3264,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
case UDAT_FRACTIONAL_SECOND_FIELD:
// Fractional seconds left-justify
- i = countDigits(text, start, pos.getIndex());
+ i = countDigits(text, start, pos.getIndex());
if (i < 3) {
while (i < 3) {
value *= 10;
@@ -3455,41 +3455,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;
- 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();
- }
+ 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;
- }
+ 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);
- 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();
- }
+ 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;
- 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();
- }
+ 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;
}
@@ -3510,26 +3510,26 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
style = UTZFMT_STYLE_GENERIC_LOCATION;
break;
}
- 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();
- }
+ 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;
- 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();
- }
+ 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;
}
@@ -3553,13 +3553,13 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
style = UTZFMT_STYLE_ISO_EXTENDED_FULL;
break;
}
- 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();
- }
+ 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;
}
@@ -3583,13 +3583,13 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
style = UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL;
break;
}
- 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();
- }
+ 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;
}
@@ -3601,21 +3601,21 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
static const UChar alt_sep = DateFormatSymbols::ALTERNATE_TIME_SEPARATOR;
// Try matching a time separator.
- int32_t count_sep = 1;
+ int32_t count_sep = 1;
UnicodeString data[3];
fSymbols->getTimeSeparatorString(data[0]);
// Add the default, if different from the locale.
if (data[0].compare(&def_sep, 1) != 0) {
- data[count_sep++].setTo(def_sep);
+ data[count_sep++].setTo(def_sep);
}
// If lenient, add also the alternate, if different from the locale.
if (isLenient() && data[0].compare(&alt_sep, 1) != 0) {
- data[count_sep++].setTo(alt_sep);
+ data[count_sep++].setTo(alt_sep);
}
- return matchString(text, start, UCAL_FIELD_COUNT /* => nothing to set */, data, count_sep, NULL, cal);
+ return matchString(text, start, UCAL_FIELD_COUNT /* => nothing to set */, data, count_sep, NULL, cal);
}
case UDAT_AM_PM_MIDNIGHT_NOON_FIELD:
@@ -3623,7 +3623,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);
+ patLoc, numericLeapMonthFormatter, tzTimeType);
if (ampmStart > 0) {
return ampmStart;
@@ -3704,7 +3704,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
}
parseInt(*src, number, pos, allowNegative,currentNumberFormat);
if (pos.getIndex() != parseStart) {
- int32_t val = number.getLong();
+ int32_t val = number.getLong();
// Don't need suffix processing here (as in number processing at the beginning of the function);
// the new fields being handled as numeric values (month, weekdays, quarters) should not have suffixes.
@@ -3712,7 +3712,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status)) {
// Check the range of the value
int32_t bias = gFieldRangeBias[patternCharIndex];
- if (bias >= 0 && (val > cal.getMaximum(field) + bias || val < cal.getMinimum(field) + bias)) {
+ if (bias >= 0 && (val > cal.getMaximum(field) + bias || val < cal.getMinimum(field) + bias)) {
return -start;
}
}
@@ -3726,35 +3726,35 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
if (!strcmp(cal.getType(),"hebrew")) {
HebrewCalendar *hc = (HebrewCalendar*)&cal;
if (cal.isSet(UCAL_YEAR)) {
- UErrorCode monthStatus = U_ZERO_ERROR;
- if (!hc->isLeapYear(hc->get(UCAL_YEAR, monthStatus)) && val >= 6) {
- cal.set(UCAL_MONTH, val);
+ UErrorCode monthStatus = U_ZERO_ERROR;
+ if (!hc->isLeapYear(hc->get(UCAL_YEAR, monthStatus)) && val >= 6) {
+ cal.set(UCAL_MONTH, val);
} else {
- cal.set(UCAL_MONTH, val - 1);
+ cal.set(UCAL_MONTH, val - 1);
}
} else {
- saveHebrewMonth = val;
+ saveHebrewMonth = val;
}
} else {
- cal.set(UCAL_MONTH, val - 1);
+ cal.set(UCAL_MONTH, val - 1);
}
break;
case UDAT_STANDALONE_MONTH_FIELD:
- cal.set(UCAL_MONTH, val - 1);
+ cal.set(UCAL_MONTH, val - 1);
break;
case UDAT_DOW_LOCAL_FIELD:
case UDAT_STANDALONE_DAY_FIELD:
- cal.set(UCAL_DOW_LOCAL, val);
+ cal.set(UCAL_DOW_LOCAL, val);
break;
case UDAT_QUARTER_FIELD:
case UDAT_STANDALONE_QUARTER_FIELD:
- cal.set(UCAL_MONTH, (val - 1) * 3);
+ cal.set(UCAL_MONTH, (val - 1) * 3);
break;
case UDAT_RELATED_YEAR_FIELD:
- cal.setRelatedYear(val);
+ cal.setRelatedYear(val);
break;
default:
- cal.set(field, val);
+ cal.set(field, val);
break;
}
return pos.getIndex();
@@ -3770,7 +3770,7 @@ void SimpleDateFormat::parseInt(const UnicodeString& text,
Formattable& number,
ParsePosition& pos,
UBool allowNegative,
- const NumberFormat *fmt) const {
+ const NumberFormat *fmt) const {
parseInt(text, number, -1, pos, allowNegative,fmt);
}
@@ -3782,18 +3782,18 @@ void SimpleDateFormat::parseInt(const UnicodeString& text,
int32_t maxDigits,
ParsePosition& pos,
UBool allowNegative,
- const NumberFormat *fmt) const {
+ const NumberFormat *fmt) const {
UnicodeString oldPrefix;
- auto* fmtAsDF = dynamic_cast<const DecimalFormat*>(fmt);
- LocalPointer<DecimalFormat> df;
- if (!allowNegative && fmtAsDF != nullptr) {
- df.adoptInstead(fmtAsDF->clone());
- if (df.isNull()) {
- // Memory allocation error
- return;
- }
+ auto* fmtAsDF = dynamic_cast<const DecimalFormat*>(fmt);
+ LocalPointer<DecimalFormat> df;
+ if (!allowNegative && fmtAsDF != nullptr) {
+ df.adoptInstead(fmtAsDF->clone());
+ if (df.isNull()) {
+ // Memory allocation error
+ return;
+ }
df->setNegativePrefix(UnicodeString(TRUE, SUPPRESS_NEGATIVE_PREFIX, -1));
- fmt = df.getAlias();
+ fmt = df.getAlias();
}
int32_t oldPos = pos.getIndex();
fmt->parse(text, number, pos);
@@ -3815,19 +3815,19 @@ void SimpleDateFormat::parseInt(const UnicodeString& text,
}
}
-int32_t SimpleDateFormat::countDigits(const UnicodeString& text, int32_t start, int32_t end) const {
- int32_t numDigits = 0;
- int32_t idx = start;
- while (idx < end) {
- UChar32 cp = text.char32At(idx);
- if (u_isdigit(cp)) {
- numDigits++;
- }
- idx += U16_LENGTH(cp);
- }
- return numDigits;
-}
-
+int32_t SimpleDateFormat::countDigits(const UnicodeString& text, int32_t start, int32_t end) const {
+ int32_t numDigits = 0;
+ int32_t idx = start;
+ while (idx < end) {
+ UChar32 cp = text.char32At(idx);
+ if (u_isdigit(cp)) {
+ numDigits++;
+ }
+ idx += U16_LENGTH(cp);
+ }
+ return numDigits;
+}
+
//----------------------------------------------------------------------
void SimpleDateFormat::translatePattern(const UnicodeString& originalPattern,
@@ -3902,42 +3902,42 @@ SimpleDateFormat::applyPattern(const UnicodeString& pattern)
{
fPattern = pattern;
parsePattern();
-
- // Hack to update use of Gannen year numbering for ja@calendar=japanese -
- // use only if format is non-numeric (includes 年) and no other fDateOverride.
- if (fCalendar != nullptr && uprv_strcmp(fCalendar->getType(),"japanese") == 0 &&
- uprv_strcmp(fLocale.getLanguage(),"ja") == 0) {
- if (fDateOverride==UnicodeString(u"y=jpanyear") && !fHasHanYearChar) {
- // Gannen numbering is set but new pattern should not use it, unset;
- // use procedure from adoptNumberFormat to clear overrides
- if (fSharedNumberFormatters) {
- freeSharedNumberFormatters(fSharedNumberFormatters);
- fSharedNumberFormatters = NULL;
- }
- fDateOverride.setToBogus(); // record status
- } else if (fDateOverride.isBogus() && fHasHanYearChar) {
- // No current override (=> no Gannen numbering) but new pattern needs it;
- // use procedures from initNUmberFormatters / adoptNumberFormat
- umtx_lock(&LOCK);
- if (fSharedNumberFormatters == NULL) {
- fSharedNumberFormatters = allocSharedNumberFormatters();
- }
- umtx_unlock(&LOCK);
- if (fSharedNumberFormatters != NULL) {
- Locale ovrLoc(fLocale.getLanguage(),fLocale.getCountry(),fLocale.getVariant(),"numbers=jpanyear");
- UErrorCode status = U_ZERO_ERROR;
- const SharedNumberFormat *snf = createSharedNumberFormat(ovrLoc, status);
- if (U_SUCCESS(status)) {
- // Now that we have an appropriate number formatter, fill in the
- // appropriate slot in the number formatters table.
- UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(u'y');
- SharedObject::copyPtr(snf, fSharedNumberFormatters[patternCharIndex]);
- snf->deleteIfZeroRefCount();
- fDateOverride.setTo(u"y=jpanyear", -1); // record status
- }
- }
- }
- }
+
+ // Hack to update use of Gannen year numbering for ja@calendar=japanese -
+ // use only if format is non-numeric (includes 年) and no other fDateOverride.
+ if (fCalendar != nullptr && uprv_strcmp(fCalendar->getType(),"japanese") == 0 &&
+ uprv_strcmp(fLocale.getLanguage(),"ja") == 0) {
+ if (fDateOverride==UnicodeString(u"y=jpanyear") && !fHasHanYearChar) {
+ // Gannen numbering is set but new pattern should not use it, unset;
+ // use procedure from adoptNumberFormat to clear overrides
+ if (fSharedNumberFormatters) {
+ freeSharedNumberFormatters(fSharedNumberFormatters);
+ fSharedNumberFormatters = NULL;
+ }
+ fDateOverride.setToBogus(); // record status
+ } else if (fDateOverride.isBogus() && fHasHanYearChar) {
+ // No current override (=> no Gannen numbering) but new pattern needs it;
+ // use procedures from initNUmberFormatters / adoptNumberFormat
+ umtx_lock(&LOCK);
+ if (fSharedNumberFormatters == NULL) {
+ fSharedNumberFormatters = allocSharedNumberFormatters();
+ }
+ umtx_unlock(&LOCK);
+ if (fSharedNumberFormatters != NULL) {
+ Locale ovrLoc(fLocale.getLanguage(),fLocale.getCountry(),fLocale.getVariant(),"numbers=jpanyear");
+ UErrorCode status = U_ZERO_ERROR;
+ const SharedNumberFormat *snf = createSharedNumberFormat(ovrLoc, status);
+ if (U_SUCCESS(status)) {
+ // Now that we have an appropriate number formatter, fill in the
+ // appropriate slot in the number formatters table.
+ UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(u'y');
+ SharedObject::copyPtr(snf, fSharedNumberFormatters[patternCharIndex]);
+ snf->deleteIfZeroRefCount();
+ fDateOverride.setTo(u"y=jpanyear", -1); // record status
+ }
+ }
+ }
+ }
}
//----------------------------------------------------------------------
@@ -3979,13 +3979,13 @@ SimpleDateFormat::setDateFormatSymbols(const DateFormatSymbols& newFormatSymbols
//----------------------------------------------------------------------
const TimeZoneFormat*
SimpleDateFormat::getTimeZoneFormat(void) const {
- // 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);
+ // 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);
}
//----------------------------------------------------------------------
@@ -4015,7 +4015,7 @@ void SimpleDateFormat::adoptCalendar(Calendar* calendarToAdopt)
DateFormatSymbols *newSymbols =
DateFormatSymbols::createForLocale(calLocale, status);
if (U_FAILURE(status)) {
- delete calendarToAdopt;
+ delete calendarToAdopt;
return;
}
DateFormat::adoptCalendar(calendarToAdopt);
@@ -4038,7 +4038,7 @@ SimpleDateFormat::setContext(UDisplayContext value, UErrorCode& status)
if (U_SUCCESS(status)) {
if ( fCapitalizationBrkIter == NULL && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE) ) {
- status = U_ZERO_ERROR;
+ status = U_ZERO_ERROR;
fCapitalizationBrkIter = BreakIterator::createSentenceInstance(fLocale, status);
if (U_FAILURE(status)) {
delete fCapitalizationBrkIter;
@@ -4253,7 +4253,7 @@ SimpleDateFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) const
// Lazy TimeZoneFormat instantiation, semantically const.
TimeZoneFormat *
-SimpleDateFormat::tzFormat(UErrorCode &status) const {
+SimpleDateFormat::tzFormat(UErrorCode &status) const {
if (fTimeZoneFormat == NULL) {
umtx_lock(&LOCK);
{
@@ -4274,7 +4274,7 @@ SimpleDateFormat::tzFormat(UErrorCode &status) const {
void SimpleDateFormat::parsePattern() {
fHasMinute = FALSE;
fHasSecond = FALSE;
- fHasHanYearChar = FALSE;
+ fHasHanYearChar = FALSE;
int len = fPattern.length();
UBool inQuote = FALSE;
@@ -4283,9 +4283,9 @@ void SimpleDateFormat::parsePattern() {
if (ch == QUOTE) {
inQuote = !inQuote;
}
- if (ch == 0x5E74) { // don't care whether this is inside quotes
- fHasHanYearChar = TRUE;
- }
+ if (ch == 0x5E74) { // don't care whether this is inside quotes
+ fHasHanYearChar = TRUE;
+ }
if (!inQuote) {
if (ch == 0x6D) { // 0x6D == 'm'
fHasMinute = TRUE;
diff --git a/contrib/libs/icu/i18n/smpdtfst.cpp b/contrib/libs/icu/i18n/smpdtfst.cpp
index db59a4b4ab..f30c085ea0 100644
--- a/contrib/libs/icu/i18n/smpdtfst.cpp
+++ b/contrib/libs/icu/i18n/smpdtfst.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/smpdtfst.h b/contrib/libs/icu/i18n/smpdtfst.h
index cc80909c88..24b0dfdd19 100644
--- a/contrib/libs/icu/i18n/smpdtfst.h
+++ b/contrib/libs/icu/i18n/smpdtfst.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -16,7 +16,7 @@
#ifndef SMPDTFST_H
#define SMPDTFST_H
-#include "unicode/uobject.h"
+#include "unicode/uobject.h"
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
diff --git a/contrib/libs/icu/i18n/sortkey.cpp b/contrib/libs/icu/i18n/sortkey.cpp
index 12289482ec..43610280a2 100644
--- a/contrib/libs/icu/i18n/sortkey.cpp
+++ b/contrib/libs/icu/i18n/sortkey.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/standardplural.cpp b/contrib/libs/icu/i18n/standardplural.cpp
index 0391034b3e..194537709c 100644
--- a/contrib/libs/icu/i18n/standardplural.cpp
+++ b/contrib/libs/icu/i18n/standardplural.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/standardplural.h b/contrib/libs/icu/i18n/standardplural.h
index 33e1d605f6..e7a9eea432 100644
--- a/contrib/libs/icu/i18n/standardplural.h
+++ b/contrib/libs/icu/i18n/standardplural.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/string_segment.cpp b/contrib/libs/icu/i18n/string_segment.cpp
index 5d19ac57f5..0393f3fd19 100644
--- a/contrib/libs/icu/i18n/string_segment.cpp
+++ b/contrib/libs/icu/i18n/string_segment.cpp
@@ -1,145 +1,145 @@
-// © 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 "string_segment.h"
-#include "putilimp.h"
-#include "unicode/utf16.h"
-#include "unicode/uniset.h"
-
-U_NAMESPACE_BEGIN
-
-
-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;
-}
-
-
-U_NAMESPACE_END
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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 "string_segment.h"
+#include "putilimp.h"
+#include "unicode/utf16.h"
+#include "unicode/uniset.h"
+
+U_NAMESPACE_BEGIN
+
+
+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;
+}
+
+
+U_NAMESPACE_END
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/string_segment.h b/contrib/libs/icu/i18n/string_segment.h
index b581f7e575..5a3d7e4c81 100644
--- a/contrib/libs/icu/i18n/string_segment.h
+++ b/contrib/libs/icu/i18n/string_segment.h
@@ -1,134 +1,134 @@
-// © 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 "unicode/unistr.h"
-#include "unicode/uniset.h"
-
-U_NAMESPACE_BEGIN
-
-
-/**
- * A mutable UnicodeString wrapper with a variable offset and length and
- * support for case folding. The charAt, length, and subSequence methods all
- * operate relative to the fixed offset into the UnicodeString.
- *
- * Intended to be useful for parsing.
- *
- * CAUTION: Since this class is mutable, it must not be used anywhere that an
- * immutable object is required, like in a cache or as the key of a hash map.
- *
- * @author sffc (Shane Carr)
- */
-// 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 <code>setOffset(getOffset()+delta)</code>.
- *
- * <p>
- * 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.
- *
- * <p>
- * <strong>Important:</strong> Most of the time, you should use {@link #startsWith}, 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.
- *
- * <p>
- * 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 UnicodeString. 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.
- *
- * <p>
- * This method only returns offsets along code point boundaries.
- *
- * <p>
- * This method will perform case folding if case folding was enabled in the constructor.
- *
- * <p>
- * 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);
-};
-
-
-U_NAMESPACE_END
-
-#endif //__NUMPARSE_STRINGSEGMENT_H__
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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 "unicode/unistr.h"
+#include "unicode/uniset.h"
+
+U_NAMESPACE_BEGIN
+
+
+/**
+ * A mutable UnicodeString wrapper with a variable offset and length and
+ * support for case folding. The charAt, length, and subSequence methods all
+ * operate relative to the fixed offset into the UnicodeString.
+ *
+ * Intended to be useful for parsing.
+ *
+ * CAUTION: Since this class is mutable, it must not be used anywhere that an
+ * immutable object is required, like in a cache or as the key of a hash map.
+ *
+ * @author sffc (Shane Carr)
+ */
+// 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 <code>setOffset(getOffset()+delta)</code>.
+ *
+ * <p>
+ * 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.
+ *
+ * <p>
+ * <strong>Important:</strong> Most of the time, you should use {@link #startsWith}, 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.
+ *
+ * <p>
+ * 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 UnicodeString. 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.
+ *
+ * <p>
+ * This method only returns offsets along code point boundaries.
+ *
+ * <p>
+ * This method will perform case folding if case folding was enabled in the constructor.
+ *
+ * <p>
+ * 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);
+};
+
+
+U_NAMESPACE_END
+
+#endif //__NUMPARSE_STRINGSEGMENT_H__
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/strmatch.cpp b/contrib/libs/icu/i18n/strmatch.cpp
index a20f7873fe..d7903bc0cf 100644
--- a/contrib/libs/icu/i18n/strmatch.cpp
+++ b/contrib/libs/icu/i18n/strmatch.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -58,7 +58,7 @@ StringMatcher::~StringMatcher() {
/**
* Implement UnicodeFunctor
*/
-StringMatcher* StringMatcher::clone() const {
+StringMatcher* StringMatcher::clone() const {
return new StringMatcher(*this);
}
diff --git a/contrib/libs/icu/i18n/strmatch.h b/contrib/libs/icu/i18n/strmatch.h
index 71ae984951..c1e0a4dbdf 100644
--- a/contrib/libs/icu/i18n/strmatch.h
+++ b/contrib/libs/icu/i18n/strmatch.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
* Copyright (C) 2001-2011, International Business Machines Corporation
@@ -78,7 +78,7 @@ class StringMatcher : public UnicodeFunctor, public UnicodeMatcher, public Unico
* Implement UnicodeFunctor
* @return a copy of the object.
*/
- virtual StringMatcher* clone() const;
+ virtual StringMatcher* clone() const;
/**
* UnicodeFunctor API. Cast 'this' to a UnicodeMatcher* pointer
diff --git a/contrib/libs/icu/i18n/strrepl.cpp b/contrib/libs/icu/i18n/strrepl.cpp
index 9fafeb2659..6b71da1ae6 100644
--- a/contrib/libs/icu/i18n/strrepl.cpp
+++ b/contrib/libs/icu/i18n/strrepl.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -87,7 +87,7 @@ StringReplacer::~StringReplacer() {
/**
* Implement UnicodeFunctor
*/
-StringReplacer* StringReplacer::clone() const {
+StringReplacer* StringReplacer::clone() const {
return new StringReplacer(*this);
}
diff --git a/contrib/libs/icu/i18n/strrepl.h b/contrib/libs/icu/i18n/strrepl.h
index 7f74d0d945..3f5969f60b 100644
--- a/contrib/libs/icu/i18n/strrepl.h
+++ b/contrib/libs/icu/i18n/strrepl.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -111,7 +111,7 @@ class StringReplacer : public UnicodeFunctor, public UnicodeReplacer {
/**
* Implement UnicodeFunctor
*/
- virtual StringReplacer* clone() const;
+ virtual StringReplacer* clone() const;
/**
* UnicodeFunctor API. Cast 'this' to a UnicodeReplacer* pointer
diff --git a/contrib/libs/icu/i18n/stsearch.cpp b/contrib/libs/icu/i18n/stsearch.cpp
index 3e6ed4648b..2e1908b054 100644
--- a/contrib/libs/icu/i18n/stsearch.cpp
+++ b/contrib/libs/icu/i18n/stsearch.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -282,7 +282,7 @@ void StringSearch::reset()
usearch_reset(m_strsrch_);
}
-StringSearch * StringSearch::safeClone() const
+StringSearch * StringSearch::safeClone() const
{
UErrorCode status = U_ZERO_ERROR;
StringSearch *result = new StringSearch(m_pattern_, m_text_,
diff --git a/contrib/libs/icu/i18n/taiwncal.cpp b/contrib/libs/icu/i18n/taiwncal.cpp
index 27352aa10c..4771e24b41 100644
--- a/contrib/libs/icu/i18n/taiwncal.cpp
+++ b/contrib/libs/icu/i18n/taiwncal.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -53,7 +53,7 @@ TaiwanCalendar& TaiwanCalendar::operator= ( const TaiwanCalendar& right)
return *this;
}
-TaiwanCalendar* TaiwanCalendar::clone() const
+TaiwanCalendar* TaiwanCalendar::clone() const
{
return new TaiwanCalendar(*this);
}
diff --git a/contrib/libs/icu/i18n/taiwncal.h b/contrib/libs/icu/i18n/taiwncal.h
index 01d4d31e80..c0bfbcddac 100644
--- a/contrib/libs/icu/i18n/taiwncal.h
+++ b/contrib/libs/icu/i18n/taiwncal.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
********************************************************************************
@@ -91,7 +91,7 @@ public:
* @return return a polymorphic copy of this calendar.
* @internal
*/
- virtual TaiwanCalendar* clone() const;
+ virtual TaiwanCalendar* clone() const;
public:
/**
diff --git a/contrib/libs/icu/i18n/timezone.cpp b/contrib/libs/icu/i18n/timezone.cpp
index 284334ebf7..2ed29b0a34 100644
--- a/contrib/libs/icu/i18n/timezone.cpp
+++ b/contrib/libs/icu/i18n/timezone.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -115,14 +115,14 @@ static const int32_t UNKNOWN_ZONE_ID_LENGTH = 11;
static icu::TimeZone* DEFAULT_ZONE = NULL;
static icu::UInitOnce gDefaultZoneInitOnce = U_INITONCE_INITIALIZER;
-alignas(icu::SimpleTimeZone)
-static char gRawGMT[sizeof(icu::SimpleTimeZone)];
-
-alignas(icu::SimpleTimeZone)
-static char gRawUNKNOWN[sizeof(icu::SimpleTimeZone)];
-
+alignas(icu::SimpleTimeZone)
+static char gRawGMT[sizeof(icu::SimpleTimeZone)];
+
+alignas(icu::SimpleTimeZone)
+static char gRawUNKNOWN[sizeof(icu::SimpleTimeZone)];
+
static icu::UInitOnce gStaticZonesInitOnce = U_INITONCE_INITIALIZER;
-static UBool gStaticZonesInitialized = FALSE; // Whether the static zones are initialized and ready to use.
+static UBool gStaticZonesInitialized = FALSE; // Whether the static zones are initialized and ready to use.
static char TZDATA_VERSION[16];
static icu::UInitOnce gTZDataVersionInitOnce = U_INITONCE_INITIALIZER;
@@ -147,12 +147,12 @@ static UBool U_CALLCONV timeZone_cleanup(void)
DEFAULT_ZONE = NULL;
gDefaultZoneInitOnce.reset();
- if (gStaticZonesInitialized) {
- reinterpret_cast<SimpleTimeZone*>(gRawGMT)->~SimpleTimeZone();
- reinterpret_cast<SimpleTimeZone*>(gRawUNKNOWN)->~SimpleTimeZone();
- gStaticZonesInitialized = FALSE;
- gStaticZonesInitOnce.reset();
- }
+ if (gStaticZonesInitialized) {
+ reinterpret_cast<SimpleTimeZone*>(gRawGMT)->~SimpleTimeZone();
+ reinterpret_cast<SimpleTimeZone*>(gRawUNKNOWN)->~SimpleTimeZone();
+ gStaticZonesInitialized = FALSE;
+ gStaticZonesInitOnce.reset();
+ }
uprv_memset(TZDATA_VERSION, 0, sizeof(TZDATA_VERSION));
gTZDataVersionInitOnce.reset();
@@ -278,7 +278,7 @@ static UResourceBundle* openOlsonResource(const UnicodeString& id,
UResourceBundle& res,
UErrorCode& ec)
{
-#ifdef U_DEBUG_TZ
+#ifdef U_DEBUG_TZ
char buf[128];
id.extract(0, sizeof(buf)-1, buf, sizeof(buf), "");
#endif
@@ -310,12 +310,12 @@ void U_CALLCONV initStaticTimeZones() {
// Initialize _GMT independently of other static data; it should
// be valid even if we can't load the time zone UDataMemory.
ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
-
- // new can't fail below, as we use placement new into staticly allocated space.
- new(gRawGMT) SimpleTimeZone(0, UnicodeString(TRUE, GMT_ID, GMT_ID_LENGTH));
- new(gRawUNKNOWN) SimpleTimeZone(0, UnicodeString(TRUE, UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH));
-
- gStaticZonesInitialized = TRUE;
+
+ // new can't fail below, as we use placement new into staticly allocated space.
+ new(gRawGMT) SimpleTimeZone(0, UnicodeString(TRUE, GMT_ID, GMT_ID_LENGTH));
+ new(gRawUNKNOWN) SimpleTimeZone(0, UnicodeString(TRUE, UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH));
+
+ gStaticZonesInitialized = TRUE;
}
} // anonymous namespace
@@ -324,14 +324,14 @@ const TimeZone& U_EXPORT2
TimeZone::getUnknown()
{
umtx_initOnce(gStaticZonesInitOnce, &initStaticTimeZones);
- return *reinterpret_cast<SimpleTimeZone*>(gRawUNKNOWN);
+ return *reinterpret_cast<SimpleTimeZone*>(gRawUNKNOWN);
}
const TimeZone* U_EXPORT2
TimeZone::getGMT(void)
{
umtx_initOnce(gStaticZonesInitOnce, &initStaticTimeZones);
- return reinterpret_cast<SimpleTimeZone*>(gRawGMT);
+ return reinterpret_cast<SimpleTimeZone*>(gRawGMT);
}
// *****************************************************************************
@@ -392,22 +392,22 @@ createSystemTimeZone(const UnicodeString& id, UErrorCode& ec) {
return NULL;
}
TimeZone* z = 0;
- StackUResourceBundle res;
+ StackUResourceBundle res;
U_DEBUG_TZ_MSG(("pre-err=%s\n", u_errorName(ec)));
- UResourceBundle *top = openOlsonResource(id, res.ref(), ec);
+ UResourceBundle *top = openOlsonResource(id, res.ref(), ec);
U_DEBUG_TZ_MSG(("post-err=%s\n", u_errorName(ec)));
if (U_SUCCESS(ec)) {
- z = new OlsonTimeZone(top, res.getAlias(), id, ec);
+ z = new OlsonTimeZone(top, res.getAlias(), id, ec);
if (z == NULL) {
- ec = U_MEMORY_ALLOCATION_ERROR;
- U_DEBUG_TZ_MSG(("cstz: olson time zone failed to initialize - err %s\n", u_errorName(ec)));
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ U_DEBUG_TZ_MSG(("cstz: olson time zone failed to initialize - err %s\n", u_errorName(ec)));
}
}
ures_close(top);
if (U_FAILURE(ec)) {
U_DEBUG_TZ_MSG(("cstz: failed to create, err %s\n", u_errorName(ec)));
delete z;
- z = NULL;
+ z = NULL;
}
return z;
}
@@ -445,8 +445,8 @@ TimeZone::createTimeZone(const UnicodeString& ID)
if (result == NULL) {
U_DEBUG_TZ_MSG(("failed to load time zone with id - falling to Etc/Unknown(GMT)"));
const TimeZone& unknown = getUnknown();
- // Unknown zone uses staticly allocated memory, so creation of it can never fail due to OOM.
- result = unknown.clone();
+ // Unknown zone uses staticly allocated memory, so creation of it can never fail due to OOM.
+ result = unknown.clone();
}
return result;
}
@@ -456,11 +456,11 @@ TimeZone::createTimeZone(const UnicodeString& ID)
TimeZone* U_EXPORT2
TimeZone::detectHostTimeZone()
{
- // We access system timezone data through uprv_tzset(), uprv_tzname(), and others,
- // which have platform specific implementations in putil.cpp
+ // We access system timezone data through uprv_tzset(), uprv_tzname(), and others,
+ // which have platform specific implementations in putil.cpp
int32_t rawOffset = 0;
const char *hostID;
- UBool hostDetectionSucceeded = TRUE;
+ UBool hostDetectionSucceeded = TRUE;
// First, try to create a system timezone, based
// on the string ID in tzname[0].
@@ -471,7 +471,7 @@ TimeZone::detectHostTimeZone()
// Get the timezone ID from the host. This function should do
// any required host-specific remapping; e.g., on Windows this
- // function maps the Windows Time Zone name to an ICU timezone ID.
+ // function maps the Windows Time Zone name to an ICU timezone ID.
hostID = uprv_tzname(0);
// Invert sign because UNIX semantics are backwards
@@ -480,14 +480,14 @@ TimeZone::detectHostTimeZone()
TimeZone* hostZone = NULL;
UnicodeString hostStrID(hostID, -1, US_INV);
-
- if (hostStrID.length() == 0) {
- // The host time zone detection (or remapping) above has failed and
- // we have no name at all. Fallback to using the Unknown zone.
- hostStrID = UnicodeString(TRUE, UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH);
- hostDetectionSucceeded = FALSE;
- }
-
+
+ if (hostStrID.length() == 0) {
+ // The host time zone detection (or remapping) above has failed and
+ // we have no name at all. Fallback to using the Unknown zone.
+ hostStrID = UnicodeString(TRUE, UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH);
+ hostDetectionSucceeded = FALSE;
+ }
+
hostZone = createSystemTimeZone(hostStrID);
#if U_PLATFORM_USES_ONLY_WIN32_API
@@ -507,19 +507,19 @@ TimeZone::detectHostTimeZone()
// Construct a fixed standard zone with the host's ID
// and raw offset.
- if (hostZone == NULL && hostDetectionSucceeded) {
+ if (hostZone == NULL && hostDetectionSucceeded) {
hostZone = new SimpleTimeZone(rawOffset, hostStrID);
}
- // If we _still_ don't have a time zone, use the Unknown zone.
+ // If we _still_ don't have a time zone, use the Unknown zone.
//
// Note: This is extremely unlikely situation. If
// new SimpleTimeZone(...) above fails, the following
// code may also fail.
if (hostZone == NULL) {
- // Unknown zone uses static allocated memory, so it must always exist.
- // However, clone() allocates memory and can fail.
- hostZone = TimeZone::getUnknown().clone();
+ // Unknown zone uses static allocated memory, so it must always exist.
+ // However, clone() allocates memory and can fail.
+ hostZone = TimeZone::getUnknown().clone();
}
return hostZone;
@@ -527,8 +527,8 @@ TimeZone::detectHostTimeZone()
// -------------------------------------
-static UMutex gDefaultZoneMutex;
-
+static UMutex gDefaultZoneMutex;
+
/**
* Initialize DEFAULT_ZONE from the system default time zone.
* Upon return, DEFAULT_ZONE will not be NULL, unless operator new()
@@ -538,7 +538,7 @@ static void U_CALLCONV initDefault()
{
ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
- Mutex lock(&gDefaultZoneMutex);
+ Mutex lock(&gDefaultZoneMutex);
// If setDefault() has already been called we can skip getting the
// default zone information from the system.
if (DEFAULT_ZONE != NULL) {
@@ -571,10 +571,10 @@ TimeZone* U_EXPORT2
TimeZone::createDefault()
{
umtx_initOnce(gDefaultZoneInitOnce, initDefault);
- {
- Mutex lock(&gDefaultZoneMutex);
- return (DEFAULT_ZONE != NULL) ? DEFAULT_ZONE->clone() : NULL;
- }
+ {
+ Mutex lock(&gDefaultZoneMutex);
+ return (DEFAULT_ZONE != NULL) ? DEFAULT_ZONE->clone() : NULL;
+ }
}
// -------------------------------------
@@ -584,12 +584,12 @@ TimeZone::adoptDefault(TimeZone* zone)
{
if (zone != NULL)
{
- {
- Mutex lock(&gDefaultZoneMutex);
- TimeZone *old = DEFAULT_ZONE;
- DEFAULT_ZONE = zone;
- delete old;
- }
+ {
+ Mutex lock(&gDefaultZoneMutex);
+ TimeZone *old = DEFAULT_ZONE;
+ DEFAULT_ZONE = zone;
+ delete old;
+ }
ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
}
}
@@ -753,7 +753,7 @@ private:
len = mapLen;
}
- UBool getID(int32_t i, UErrorCode& ec) {
+ UBool getID(int32_t i, UErrorCode& ec) {
int32_t idLen = 0;
const UChar* id = NULL;
UResourceBundle *top = ures_openDirect(0, kZONEINFO, &ec);
@@ -943,7 +943,7 @@ public:
virtual const UnicodeString* snext(UErrorCode& status) {
if (U_SUCCESS(status) && map != NULL && pos < len) {
- getID(map[pos], status);
+ getID(map[pos], status);
++pos;
return &unistr;
}
@@ -1000,13 +1000,13 @@ int32_t U_EXPORT2
TimeZone::countEquivalentIDs(const UnicodeString& id) {
int32_t result = 0;
UErrorCode ec = U_ZERO_ERROR;
- StackUResourceBundle res;
+ StackUResourceBundle res;
U_DEBUG_TZ_MSG(("countEquivalentIDs..\n"));
- UResourceBundle *top = openOlsonResource(id, res.ref(), ec);
+ UResourceBundle *top = openOlsonResource(id, res.ref(), ec);
if (U_SUCCESS(ec)) {
- StackUResourceBundle r;
- ures_getByKey(res.getAlias(), kLINKS, r.getAlias(), &ec);
- ures_getIntVector(r.getAlias(), &result, &ec);
+ StackUResourceBundle r;
+ ures_getByKey(res.getAlias(), kLINKS, r.getAlias(), &ec);
+ ures_getIntVector(r.getAlias(), &result, &ec);
}
ures_close(top);
return result;
@@ -1019,14 +1019,14 @@ TimeZone::getEquivalentID(const UnicodeString& id, int32_t index) {
U_DEBUG_TZ_MSG(("gEI(%d)\n", index));
UnicodeString result;
UErrorCode ec = U_ZERO_ERROR;
- StackUResourceBundle res;
- UResourceBundle *top = openOlsonResource(id, res.ref(), ec);
+ StackUResourceBundle res;
+ UResourceBundle *top = openOlsonResource(id, res.ref(), ec);
int32_t zone = -1;
if (U_SUCCESS(ec)) {
- StackUResourceBundle r;
+ StackUResourceBundle r;
int32_t size;
- ures_getByKey(res.getAlias(), kLINKS, r.getAlias(), &ec);
- const int32_t *v = ures_getIntVector(r.getAlias(), &size, &ec);
+ ures_getByKey(res.getAlias(), kLINKS, r.getAlias(), &ec);
+ const int32_t *v = ures_getIntVector(r.getAlias(), &size, &ec);
if (U_SUCCESS(ec)) {
if (index >= 0 && index < size) {
zone = v[index];
@@ -1037,8 +1037,8 @@ TimeZone::getEquivalentID(const UnicodeString& id, int32_t index) {
UResourceBundle *ares = ures_getByKey(top, kNAMES, NULL, &ec); // dereference Zones section
if (U_SUCCESS(ec)) {
int32_t idLen = 0;
- const UChar* id2 = ures_getStringByIndex(ares, zone, &idLen, &ec);
- result.fastCopyFrom(UnicodeString(TRUE, id2, idLen));
+ const UChar* id2 = ures_getStringByIndex(ares, zone, &idLen, &ec);
+ result.fastCopyFrom(UnicodeString(TRUE, id2, idLen));
U_DEBUG_TZ_MSG(("gei(%d) -> %d, len%d, %s\n", index, zone, result.length(), u_errorName(ec)));
}
ures_close(ares);
@@ -1187,9 +1187,9 @@ TimeZone::getDisplayName(const Locale& locale, UnicodeString& result) const
}
UnicodeString&
-TimeZone::getDisplayName(UBool inDaylight, EDisplayType style, UnicodeString& result) const
+TimeZone::getDisplayName(UBool inDaylight, EDisplayType style, UnicodeString& result) const
{
- return getDisplayName(inDaylight,style, Locale::getDefault(), result);
+ return getDisplayName(inDaylight,style, Locale::getDefault(), result);
}
//--------------------------------------
int32_t
@@ -1201,11 +1201,11 @@ TimeZone::getDSTSavings()const {
}
//---------------------------------------
UnicodeString&
-TimeZone::getDisplayName(UBool inDaylight, EDisplayType style, const Locale& locale, UnicodeString& result) const
+TimeZone::getDisplayName(UBool inDaylight, EDisplayType style, const Locale& locale, UnicodeString& result) const
{
UErrorCode status = U_ZERO_ERROR;
UDate date = Calendar::getNow();
- UTimeZoneFormatTimeType timeType = UTZFMT_TIME_TYPE_UNKNOWN;
+ UTimeZoneFormatTimeType timeType = UTZFMT_TIME_TYPE_UNKNOWN;
int32_t offset;
if (style == GENERIC_LOCATION || style == LONG_GENERIC || style == SHORT_GENERIC) {
@@ -1226,13 +1226,13 @@ TimeZone::getDisplayName(UBool inDaylight, EDisplayType style, const Locale& loc
tzfmt->format(UTZFMT_STYLE_GENERIC_SHORT, *this, date, result, &timeType);
break;
default:
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
// Generic format many use Localized GMT as the final fallback.
// When Localized GMT format is used, the result might not be
// appropriate for the requested daylight value.
- if ((inDaylight && timeType == UTZFMT_TIME_TYPE_STANDARD) || (!inDaylight && timeType == UTZFMT_TIME_TYPE_DAYLIGHT)) {
- offset = inDaylight ? getRawOffset() + getDSTSavings() : getRawOffset();
+ if ((inDaylight && timeType == UTZFMT_TIME_TYPE_STANDARD) || (!inDaylight && timeType == UTZFMT_TIME_TYPE_DAYLIGHT)) {
+ offset = inDaylight ? getRawOffset() + getDSTSavings() : getRawOffset();
if (style == SHORT_GENERIC) {
tzfmt->formatOffsetShortLocalizedGMT(offset, result, status);
} else {
@@ -1245,7 +1245,7 @@ TimeZone::getDisplayName(UBool inDaylight, EDisplayType style, const Locale& loc
result.remove();
return result;
}
- offset = inDaylight && useDaylightTime() ? getRawOffset() + getDSTSavings() : getRawOffset();
+ offset = inDaylight && useDaylightTime() ? getRawOffset() + getDSTSavings() : getRawOffset();
switch (style) {
case LONG_GMT:
tzfmt->formatOffsetLocalizedGMT(offset, result, status);
@@ -1254,7 +1254,7 @@ TimeZone::getDisplayName(UBool inDaylight, EDisplayType style, const Locale& loc
tzfmt->formatOffsetISO8601Basic(offset, FALSE, FALSE, FALSE, result, status);
break;
default:
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
} else {
@@ -1262,14 +1262,14 @@ TimeZone::getDisplayName(UBool inDaylight, EDisplayType style, const Locale& loc
UTimeZoneNameType nameType = UTZNM_UNKNOWN;
switch (style) {
case LONG:
- nameType = inDaylight ? UTZNM_LONG_DAYLIGHT : UTZNM_LONG_STANDARD;
+ nameType = inDaylight ? UTZNM_LONG_DAYLIGHT : UTZNM_LONG_STANDARD;
break;
case SHORT:
case SHORT_COMMONLY_USED:
- nameType = inDaylight ? UTZNM_SHORT_DAYLIGHT : UTZNM_SHORT_STANDARD;
+ nameType = inDaylight ? UTZNM_SHORT_DAYLIGHT : UTZNM_SHORT_STANDARD;
break;
default:
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
LocalPointer<TimeZoneNames> tznames(TimeZoneNames::createInstance(locale, status));
if (U_FAILURE(status)) {
@@ -1281,7 +1281,7 @@ TimeZone::getDisplayName(UBool inDaylight, EDisplayType style, const Locale& loc
if (result.isEmpty()) {
// Fallback to localized GMT
LocalPointer<TimeZoneFormat> tzfmt(TimeZoneFormat::createInstance(locale, status));
- offset = inDaylight && useDaylightTime() ? getRawOffset() + getDSTSavings() : getRawOffset();
+ offset = inDaylight && useDaylightTime() ? getRawOffset() + getDSTSavings() : getRawOffset();
if (style == LONG) {
tzfmt->formatOffsetLocalizedGMT(offset, result, status);
} else {
@@ -1502,9 +1502,9 @@ TimeZone::hasSameRules(const TimeZone& other) const
static void U_CALLCONV initTZDataVersion(UErrorCode &status) {
ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
int32_t len = 0;
- StackUResourceBundle bundle;
- ures_openDirectFillIn(bundle.getAlias(), NULL, kZONEINFO, &status);
- const UChar *tzver = ures_getStringByKey(bundle.getAlias(), kTZVERSION, &len, &status);
+ StackUResourceBundle bundle;
+ ures_openDirectFillIn(bundle.getAlias(), NULL, kZONEINFO, &status);
+ const UChar *tzver = ures_getStringByKey(bundle.getAlias(), kTZVERSION, &len, &status);
if (U_SUCCESS(status)) {
if (len >= (int32_t)sizeof(TZDATA_VERSION)) {
@@ -1617,7 +1617,7 @@ TimeZone::getWindowsID(const UnicodeString& id, UnicodeString& winid, UErrorCode
end = tzids + len;
hasNext = FALSE;
}
- if (canonicalID.compare(start, static_cast<int32_t>(end - start)) == 0) {
+ if (canonicalID.compare(start, static_cast<int32_t>(end - start)) == 0) {
winid = UnicodeString(ures_getKey(winzone), -1 , US_INV);
found = TRUE;
break;
@@ -1678,7 +1678,7 @@ TimeZone::getIDForWindowsID(const UnicodeString& winid, const char* region, Unic
if (end == NULL) {
id.setTo(tzids, -1);
} else {
- id.setTo(tzids, static_cast<int32_t>(end - tzids));
+ id.setTo(tzids, static_cast<int32_t>(end - tzids));
}
gotID = TRUE;
}
diff --git a/contrib/libs/icu/i18n/titletrn.cpp b/contrib/libs/icu/i18n/titletrn.cpp
index 9c39b4676a..9027838a91 100644
--- a/contrib/libs/icu/i18n/titletrn.cpp
+++ b/contrib/libs/icu/i18n/titletrn.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -60,7 +60,7 @@ TitlecaseTransliterator::TitlecaseTransliterator(const TitlecaseTransliterator&
/**
* Transliterator API.
*/
-TitlecaseTransliterator* TitlecaseTransliterator::clone() const {
+TitlecaseTransliterator* TitlecaseTransliterator::clone() const {
return new TitlecaseTransliterator(*this);
}
@@ -97,7 +97,7 @@ void TitlecaseTransliterator::handleTransliterate(
int32_t start;
for (start = offsets.start - 1; start >= offsets.contextStart; start -= U16_LENGTH(c)) {
c = text.char32At(start);
- type=ucase_getTypeOrIgnorable(c);
+ type=ucase_getTypeOrIgnorable(c);
if(type>0) { // cased
doTitle=FALSE;
break;
@@ -118,19 +118,19 @@ void TitlecaseTransliterator::handleTransliterate(
UnicodeString tmp;
const UChar *s;
- int32_t textPos, delta, result;
+ int32_t textPos, delta, result;
for(textPos=offsets.start; textPos<offsets.limit;) {
csc.cpStart=textPos;
c=text.char32At(textPos);
csc.cpLimit=textPos+=U16_LENGTH(c);
- type=ucase_getTypeOrIgnorable(c);
+ type=ucase_getTypeOrIgnorable(c);
if(type>=0) { // not case-ignorable
if(doTitle) {
- result=ucase_toFullTitle(c, utrans_rep_caseContextIterator, &csc, &s, UCASE_LOC_ROOT);
+ result=ucase_toFullTitle(c, utrans_rep_caseContextIterator, &csc, &s, UCASE_LOC_ROOT);
} else {
- result=ucase_toFullLower(c, utrans_rep_caseContextIterator, &csc, &s, UCASE_LOC_ROOT);
+ result=ucase_toFullLower(c, utrans_rep_caseContextIterator, &csc, &s, UCASE_LOC_ROOT);
}
doTitle = (UBool)(type==0); // doTitle=isUncased
diff --git a/contrib/libs/icu/i18n/titletrn.h b/contrib/libs/icu/i18n/titletrn.h
index 4e45ac6f81..04e64f3406 100644
--- a/contrib/libs/icu/i18n/titletrn.h
+++ b/contrib/libs/icu/i18n/titletrn.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -52,7 +52,7 @@ class TitlecaseTransliterator : public CaseMapTransliterator {
* Transliterator API.
* @return a copy of the object.
*/
- virtual TitlecaseTransliterator* clone() const;
+ virtual TitlecaseTransliterator* clone() const;
/**
* ICU "poor man's RTTI", returns a UClassID for the actual class.
diff --git a/contrib/libs/icu/i18n/tmunit.cpp b/contrib/libs/icu/i18n/tmunit.cpp
index 910489b178..5f29a8f34a 100644
--- a/contrib/libs/icu/i18n/tmunit.cpp
+++ b/contrib/libs/icu/i18n/tmunit.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -94,7 +94,7 @@ TimeUnit::TimeUnit(TimeUnit::UTimeUnitFields timeUnitField) {
initTime("second");
break;
default:
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
}
@@ -102,7 +102,7 @@ TimeUnit::TimeUnit(const TimeUnit& other)
: MeasureUnit(other), fTimeUnitField(other.fTimeUnitField) {
}
-TimeUnit*
+TimeUnit*
TimeUnit::clone() const {
return new TimeUnit(*this);
}
diff --git a/contrib/libs/icu/i18n/tmutamt.cpp b/contrib/libs/icu/i18n/tmutamt.cpp
index 25464693ea..d221d23170 100644
--- a/contrib/libs/icu/i18n/tmutamt.cpp
+++ b/contrib/libs/icu/i18n/tmutamt.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -50,7 +50,7 @@ TimeUnitAmount::operator==(const UObject& other) const {
return Measure::operator==(other);
}
-TimeUnitAmount*
+TimeUnitAmount*
TimeUnitAmount::clone() const {
return new TimeUnitAmount(*this);
}
diff --git a/contrib/libs/icu/i18n/tmutfmt.cpp b/contrib/libs/icu/i18n/tmutfmt.cpp
index 231ea5799c..4ee9f2db6b 100644
--- a/contrib/libs/icu/i18n/tmutfmt.cpp
+++ b/contrib/libs/icu/i18n/tmutfmt.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -136,8 +136,8 @@ TimeUnitFormat::~TimeUnitFormat() {
}
-TimeUnitFormat*
-TimeUnitFormat::clone() const {
+TimeUnitFormat*
+TimeUnitFormat::clone() const {
return new TimeUnitFormat(*this);
}
@@ -224,7 +224,7 @@ TimeUnitFormat::parseObject(const UnicodeString& source,
if (temp.getType() == Formattable::kString) {
UnicodeString tmpString;
UErrorCode pStatus = U_ZERO_ERROR;
- getNumberFormatInternal().parse(temp.getString(tmpString), tmpNumber, pStatus);
+ getNumberFormatInternal().parse(temp.getString(tmpString), tmpNumber, pStatus);
if (U_FAILURE(pStatus)) {
continue;
}
@@ -685,7 +685,7 @@ TimeUnitFormat::setNumberFormat(const NumberFormat& format, UErrorCode& status){
if (U_FAILURE(status)) {
return;
}
- adoptNumberFormat(format.clone(), status);
+ adoptNumberFormat(format.clone(), status);
}
@@ -721,8 +721,8 @@ TimeUnitFormat::copyHash(const Hashtable* source, Hashtable* target, UErrorCode&
const UHashTok valueTok = element->value;
const MessageFormat** value = (const MessageFormat**)valueTok.pointer;
MessageFormat** newVal = (MessageFormat**)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT*sizeof(MessageFormat*));
- newVal[0] = value[0]->clone();
- newVal[1] = value[1]->clone();
+ newVal[0] = value[0]->clone();
+ newVal[1] = value[1]->clone();
target->put(UnicodeString(*key), newVal, status);
if ( U_FAILURE(status) ) {
delete newVal[0];
diff --git a/contrib/libs/icu/i18n/tolowtrn.cpp b/contrib/libs/icu/i18n/tolowtrn.cpp
index 289327874e..8eed19c218 100644
--- a/contrib/libs/icu/i18n/tolowtrn.cpp
+++ b/contrib/libs/icu/i18n/tolowtrn.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -58,7 +58,7 @@ LowercaseTransliterator::LowercaseTransliterator(const LowercaseTransliterator&
/**
* Transliterator API.
*/
-LowercaseTransliterator* LowercaseTransliterator::clone() const {
+LowercaseTransliterator* LowercaseTransliterator::clone() const {
return new LowercaseTransliterator(*this);
}
diff --git a/contrib/libs/icu/i18n/tolowtrn.h b/contrib/libs/icu/i18n/tolowtrn.h
index 2fbfb90e1b..ce86f27d22 100644
--- a/contrib/libs/icu/i18n/tolowtrn.h
+++ b/contrib/libs/icu/i18n/tolowtrn.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -50,7 +50,7 @@ class LowercaseTransliterator : public CaseMapTransliterator {
* Transliterator API.
* @return a copy of the object.
*/
- virtual LowercaseTransliterator* clone() const;
+ virtual LowercaseTransliterator* clone() const;
/**
* ICU "poor man's RTTI", returns a UClassID for the actual class.
diff --git a/contrib/libs/icu/i18n/toupptrn.cpp b/contrib/libs/icu/i18n/toupptrn.cpp
index 2a8b78b9a6..06311b5049 100644
--- a/contrib/libs/icu/i18n/toupptrn.cpp
+++ b/contrib/libs/icu/i18n/toupptrn.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -58,7 +58,7 @@ UppercaseTransliterator::UppercaseTransliterator(const UppercaseTransliterator&
/**
* Transliterator API.
*/
-UppercaseTransliterator* UppercaseTransliterator::clone() const {
+UppercaseTransliterator* UppercaseTransliterator::clone() const {
return new UppercaseTransliterator(*this);
}
diff --git a/contrib/libs/icu/i18n/toupptrn.h b/contrib/libs/icu/i18n/toupptrn.h
index e96ca8f0ba..bdc77ca55c 100644
--- a/contrib/libs/icu/i18n/toupptrn.h
+++ b/contrib/libs/icu/i18n/toupptrn.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -50,7 +50,7 @@ class UppercaseTransliterator : public CaseMapTransliterator {
* Transliterator API.
* @return a copy of the object.
*/
- virtual UppercaseTransliterator* clone() const;
+ virtual UppercaseTransliterator* clone() const;
/**
* ICU "poor man's RTTI", returns a UClassID for the actual class.
diff --git a/contrib/libs/icu/i18n/translit.cpp b/contrib/libs/icu/i18n/translit.cpp
index ef44f42aa6..b497d1aa87 100644
--- a/contrib/libs/icu/i18n/translit.cpp
+++ b/contrib/libs/icu/i18n/translit.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -91,7 +91,7 @@ static const char RB_RULE_BASED_IDS[] = "RuleBasedTransliteratorIDs";
/**
* The mutex controlling access to registry object.
*/
-static icu::UMutex registryMutex;
+static icu::UMutex registryMutex;
/**
* System transliterator registry; non-null when initialized.
@@ -158,7 +158,7 @@ Transliterator::Transliterator(const Transliterator& other) :
if (other.filter != 0) {
// We own the filter, so we must have our own copy
- filter = other.filter->clone();
+ filter = other.filter->clone();
}
}
@@ -175,7 +175,7 @@ Transliterator& Transliterator::operator=(const Transliterator& other) {
ID.getTerminatedBuffer();
maximumContextLength = other.maximumContextLength;
- adoptFilter((other.filter == 0) ? 0 : other.filter->clone());
+ adoptFilter((other.filter == 0) ? 0 : other.filter->clone());
return *this;
}
@@ -923,15 +923,15 @@ Transliterator::createInstance(const UnicodeString& ID,
return NULL;
}
- UnicodeSet* globalFilter = nullptr;
+ UnicodeSet* globalFilter = nullptr;
// TODO add code for parseError...currently unused, but
// later may be used by parsing code...
if (!TransliteratorIDParser::parseCompoundID(ID, dir, canonID, list, globalFilter)) {
status = U_INVALID_ID;
- delete globalFilter;
+ delete globalFilter;
return NULL;
}
- LocalPointer<UnicodeSet> lpGlobalFilter(globalFilter);
+ LocalPointer<UnicodeSet> lpGlobalFilter(globalFilter);
TransliteratorIDParser::instantiateList(list, status);
if (U_FAILURE(status)) {
@@ -955,8 +955,8 @@ Transliterator::createInstance(const UnicodeString& ID,
// Check null pointer
if (t != NULL) {
t->setID(canonID);
- if (lpGlobalFilter.isValid()) {
- t->adoptFilter(lpGlobalFilter.orphan());
+ if (lpGlobalFilter.isValid()) {
+ t->adoptFilter(lpGlobalFilter.orphan());
}
}
else if (U_SUCCESS(status)) {
@@ -1103,10 +1103,10 @@ Transliterator::createFromRules(const UnicodeString& ID,
UnicodeString* idBlock = (UnicodeString*)parser.idBlockVector.elementAt(i);
if (!idBlock->isEmpty()) {
Transliterator* temp = createInstance(*idBlock, UTRANS_FORWARD, parseError, status);
- if (U_FAILURE(status)) {
- delete temp;
- return nullptr;
- }
+ if (U_FAILURE(status)) {
+ delete temp;
+ return nullptr;
+ }
if (temp != NULL && typeid(*temp) != typeid(NullTransliterator))
transliterators.addElement(temp, status);
else
@@ -1120,10 +1120,10 @@ Transliterator::createFromRules(const UnicodeString& ID,
data, TRUE);
// Check if NULL before adding it to transliterators to avoid future usage of NULL pointer.
if (temprbt == NULL) {
- if (U_SUCCESS(status)) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
- return t;
+ if (U_SUCCESS(status)) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return t;
}
transliterators.addElement(temprbt, status);
}
@@ -1508,35 +1508,35 @@ UBool Transliterator::initializeRegistry(UErrorCode &status) {
*/
//static const char translit_index[] = "translit_index";
- UErrorCode lstatus = U_ZERO_ERROR;
+ UErrorCode lstatus = U_ZERO_ERROR;
UResourceBundle *bundle, *transIDs, *colBund;
- bundle = ures_open(U_ICUDATA_TRANSLIT, NULL/*open default locale*/, &lstatus);
- transIDs = ures_getByKey(bundle, RB_RULE_BASED_IDS, 0, &lstatus);
+ bundle = ures_open(U_ICUDATA_TRANSLIT, NULL/*open default locale*/, &lstatus);
+ transIDs = ures_getByKey(bundle, RB_RULE_BASED_IDS, 0, &lstatus);
const UnicodeString T_PART = UNICODE_STRING_SIMPLE("-t-");
int32_t row, maxRows;
- if (lstatus == U_MEMORY_ALLOCATION_ERROR) {
- delete registry;
- registry = nullptr;
- status = U_MEMORY_ALLOCATION_ERROR;
- return FALSE;
- }
- if (U_SUCCESS(lstatus)) {
+ if (lstatus == U_MEMORY_ALLOCATION_ERROR) {
+ delete registry;
+ registry = nullptr;
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return FALSE;
+ }
+ if (U_SUCCESS(lstatus)) {
maxRows = ures_getSize(transIDs);
for (row = 0; row < maxRows; row++) {
- colBund = ures_getByIndex(transIDs, row, 0, &lstatus);
- if (U_SUCCESS(lstatus)) {
+ colBund = ures_getByIndex(transIDs, row, 0, &lstatus);
+ if (U_SUCCESS(lstatus)) {
UnicodeString id(ures_getKey(colBund), -1, US_INV);
if(id.indexOf(T_PART) != -1) {
ures_close(colBund);
continue;
}
- UResourceBundle* res = ures_getNextResource(colBund, NULL, &lstatus);
+ UResourceBundle* res = ures_getNextResource(colBund, NULL, &lstatus);
const char* typeStr = ures_getKey(res);
UChar type;
u_charsToUChars(typeStr, &type, 1);
- if (U_SUCCESS(lstatus)) {
+ if (U_SUCCESS(lstatus)) {
int32_t len = 0;
const UChar *resString;
switch (type) {
@@ -1546,19 +1546,19 @@ UBool Transliterator::initializeRegistry(UErrorCode &status) {
// row[2]=resource, row[3]=direction
{
- resString = ures_getStringByKey(res, "resource", &len, &lstatus);
+ resString = ures_getStringByKey(res, "resource", &len, &lstatus);
UBool visible = (type == 0x0066 /*f*/);
UTransDirection dir =
- (ures_getUnicodeStringByKey(res, "direction", &lstatus).charAt(0) ==
+ (ures_getUnicodeStringByKey(res, "direction", &lstatus).charAt(0) ==
0x0046 /*F*/) ?
UTRANS_FORWARD : UTRANS_REVERSE;
- registry->put(id, UnicodeString(TRUE, resString, len), dir, TRUE, visible, lstatus);
+ registry->put(id, UnicodeString(TRUE, resString, len), dir, TRUE, visible, lstatus);
}
break;
case 0x61: // 'a'
// 'alias'; row[2]=createInstance argument
- resString = ures_getString(res, &len, &lstatus);
- registry->put(id, UnicodeString(TRUE, resString, len), TRUE, TRUE, lstatus);
+ resString = ures_getString(res, &len, &lstatus);
+ registry->put(id, UnicodeString(TRUE, resString, len), TRUE, TRUE, lstatus);
break;
}
}
diff --git a/contrib/libs/icu/i18n/transreg.cpp b/contrib/libs/icu/i18n/transreg.cpp
index c412a20079..dae00b0c0b 100644
--- a/contrib/libs/icu/i18n/transreg.cpp
+++ b/contrib/libs/icu/i18n/transreg.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -46,29 +46,29 @@ static const UChar LOCALE_SEP = 95; // '_'
//static const UChar VARIANT_SEP = 0x002F; // '/'
// String constants
-static const UChar ANY[] = { 0x41, 0x6E, 0x79, 0 }; // Any
-static const UChar LAT[] = { 0x4C, 0x61, 0x74, 0 }; // Lat
+static const UChar ANY[] = { 0x41, 0x6E, 0x79, 0 }; // Any
+static const UChar LAT[] = { 0x4C, 0x61, 0x74, 0 }; // Lat
// empty string
#define NO_VARIANT UnicodeString()
-// initial estimate for specDAG size
-// ICU 60 Transliterator::countAvailableSources()
-#define SPECDAG_INIT_SIZE 149
-
-// initial estimate for number of variant names
-#define VARIANT_LIST_INIT_SIZE 11
-#define VARIANT_LIST_MAX_SIZE 31
-
-// initial estimate for availableIDs count (default estimate is 8 => multiple reallocs)
-// ICU 60 Transliterator::countAvailableIDs()
-#define AVAILABLE_IDS_INIT_SIZE 641
-
-// initial estimate for number of targets for source "Any", "Lat"
-// ICU 60 Transliterator::countAvailableTargets("Any")/("Latn")
-#define ANY_TARGETS_INIT_SIZE 125
-#define LAT_TARGETS_INIT_SIZE 23
-
+// initial estimate for specDAG size
+// ICU 60 Transliterator::countAvailableSources()
+#define SPECDAG_INIT_SIZE 149
+
+// initial estimate for number of variant names
+#define VARIANT_LIST_INIT_SIZE 11
+#define VARIANT_LIST_MAX_SIZE 31
+
+// initial estimate for availableIDs count (default estimate is 8 => multiple reallocs)
+// ICU 60 Transliterator::countAvailableIDs()
+#define AVAILABLE_IDS_INIT_SIZE 641
+
+// initial estimate for number of targets for source "Any", "Lat"
+// ICU 60 Transliterator::countAvailableTargets("Any")/("Latn")
+#define ANY_TARGETS_INIT_SIZE 125
+#define LAT_TARGETS_INIT_SIZE 23
+
/**
* Resource bundle key for the RuleBasedTransliterator rule.
*/
@@ -131,7 +131,7 @@ Transliterator* TransliteratorAlias::create(UParseError& pe,
return 0;
}
if (compoundFilter != 0)
- t->adoptFilter(compoundFilter->clone());
+ t->adoptFilter(compoundFilter->clone());
break;
case COMPOUND:
{
@@ -173,8 +173,8 @@ Transliterator* TransliteratorAlias::create(UParseError& pe,
if (U_SUCCESS(ec)) {
t = new CompoundTransliterator(ID, transliterators,
- (compoundFilter ? compoundFilter->clone() : nullptr),
- anonymousRBTs, pe, ec);
+ (compoundFilter ? compoundFilter->clone() : nullptr),
+ anonymousRBTs, pe, ec);
if (t == 0) {
ec = U_MEMORY_ALLOCATION_ERROR;
return 0;
@@ -186,7 +186,7 @@ Transliterator* TransliteratorAlias::create(UParseError& pe,
}
break;
case RULES:
- UPRV_UNREACHABLE; // don't call create() if isRuleBased() returns TRUE!
+ UPRV_UNREACHABLE; // don't call create() if isRuleBased() returns TRUE!
}
return t;
}
@@ -534,17 +534,17 @@ U_CDECL_END
TransliteratorRegistry::TransliteratorRegistry(UErrorCode& status) :
registry(TRUE, status),
- specDAG(TRUE, SPECDAG_INIT_SIZE, status),
- variantList(VARIANT_LIST_INIT_SIZE, status),
- availableIDs(AVAILABLE_IDS_INIT_SIZE, status)
+ specDAG(TRUE, SPECDAG_INIT_SIZE, status),
+ variantList(VARIANT_LIST_INIT_SIZE, status),
+ availableIDs(AVAILABLE_IDS_INIT_SIZE, status)
{
registry.setValueDeleter(deleteEntry);
- variantList.setDeleter(uprv_deleteUObject);
- variantList.setComparer(uhash_compareCaselessUnicodeString);
- UnicodeString *emptyString = new UnicodeString();
- if (emptyString != NULL) {
- variantList.addElement(emptyString, status);
- }
+ variantList.setDeleter(uprv_deleteUObject);
+ variantList.setComparer(uhash_compareCaselessUnicodeString);
+ UnicodeString *emptyString = new UnicodeString();
+ if (emptyString != NULL) {
+ variantList.addElement(emptyString, status);
+ }
availableIDs.setDeleter(uprv_deleteUObject);
availableIDs.setComparer(uhash_compareCaselessUnicodeString);
specDAG.setValueDeleter(uhash_deleteHashtable);
@@ -805,15 +805,15 @@ int32_t TransliteratorRegistry::countAvailableVariants(const UnicodeString& sour
if (targets == 0) {
return 0;
}
- uint32_t varMask = targets->geti(target);
- int32_t varCount = 0;
- while (varMask > 0) {
- if (varMask & 1) {
- varCount++;
- }
- varMask >>= 1;
- }
- return varCount;
+ uint32_t varMask = targets->geti(target);
+ int32_t varCount = 0;
+ while (varMask > 0) {
+ if (varMask & 1) {
+ varCount++;
+ }
+ varMask >>= 1;
+ }
+ return varCount;
}
UnicodeString& TransliteratorRegistry::getAvailableVariant(int32_t index,
@@ -825,25 +825,25 @@ UnicodeString& TransliteratorRegistry::getAvailableVariant(int32_t index,
result.truncate(0); // invalid source
return result;
}
- uint32_t varMask = targets->geti(target);
- int32_t varCount = 0;
- int32_t varListIndex = 0;
- while (varMask > 0) {
- if (varMask & 1) {
- if (varCount == index) {
- UnicodeString *v = (UnicodeString*) variantList.elementAt(varListIndex);
- if (v != NULL) {
- result = *v;
- return result;
- }
- break;
- }
- varCount++;
- }
- varMask >>= 1;
- varListIndex++;
+ uint32_t varMask = targets->geti(target);
+ int32_t varCount = 0;
+ int32_t varListIndex = 0;
+ while (varMask > 0) {
+ if (varMask & 1) {
+ if (varCount == index) {
+ UnicodeString *v = (UnicodeString*) variantList.elementAt(varListIndex);
+ if (v != NULL) {
+ result = *v;
+ return result;
+ }
+ break;
+ }
+ varCount++;
+ }
+ varMask >>= 1;
+ varListIndex++;
}
- result.truncate(0); // invalid target or index
+ result.truncate(0); // invalid target or index
return result;
}
@@ -946,12 +946,12 @@ void TransliteratorRegistry::registerEntry(const UnicodeString& ID,
if (visible) {
registerSTV(source, target, variant);
if (!availableIDs.contains((void*) &ID)) {
- UnicodeString *newID = ID.clone();
+ UnicodeString *newID = ID.clone();
// Check to make sure newID was created.
if (newID != NULL) {
- // NUL-terminate the ID string
- newID->getTerminatedBuffer();
- availableIDs.addElement(newID, status);
+ // NUL-terminate the ID string
+ newID->getTerminatedBuffer();
+ availableIDs.addElement(newID, status);
}
}
} else {
@@ -962,7 +962,7 @@ void TransliteratorRegistry::registerEntry(const UnicodeString& ID,
/**
* Register a source-target/variant in the specDAG. Variant may be
- * empty, but source and target must not be.
+ * empty, but source and target must not be.
*/
void TransliteratorRegistry::registerSTV(const UnicodeString& source,
const UnicodeString& target,
@@ -972,38 +972,38 @@ void TransliteratorRegistry::registerSTV(const UnicodeString& source,
UErrorCode status = U_ZERO_ERROR;
Hashtable *targets = (Hashtable*) specDAG.get(source);
if (targets == 0) {
- int32_t size = 3;
- if (source.compare(ANY,3) == 0) {
- size = ANY_TARGETS_INIT_SIZE;
- } else if (source.compare(LAT,3) == 0) {
- size = LAT_TARGETS_INIT_SIZE;
- }
- targets = new Hashtable(TRUE, size, status);
- if (U_FAILURE(status) || targets == NULL) {
+ int32_t size = 3;
+ if (source.compare(ANY,3) == 0) {
+ size = ANY_TARGETS_INIT_SIZE;
+ } else if (source.compare(LAT,3) == 0) {
+ size = LAT_TARGETS_INIT_SIZE;
+ }
+ targets = new Hashtable(TRUE, size, status);
+ if (U_FAILURE(status) || targets == NULL) {
return;
}
specDAG.put(source, targets, status);
}
- int32_t variantListIndex = variantList.indexOf((void*) &variant, 0);
- if (variantListIndex < 0) {
- if (variantList.size() >= VARIANT_LIST_MAX_SIZE) {
- // can't handle any more variants
+ int32_t variantListIndex = variantList.indexOf((void*) &variant, 0);
+ if (variantListIndex < 0) {
+ if (variantList.size() >= VARIANT_LIST_MAX_SIZE) {
+ // can't handle any more variants
return;
}
- UnicodeString *variantEntry = new UnicodeString(variant);
- if (variantEntry != NULL) {
- variantList.addElement(variantEntry, status);
- if (U_SUCCESS(status)) {
- variantListIndex = variantList.size() - 1;
- }
- }
- if (variantListIndex < 0) {
- return;
+ UnicodeString *variantEntry = new UnicodeString(variant);
+ if (variantEntry != NULL) {
+ variantList.addElement(variantEntry, status);
+ if (U_SUCCESS(status)) {
+ variantListIndex = variantList.size() - 1;
+ }
}
+ if (variantListIndex < 0) {
+ return;
+ }
}
- uint32_t addMask = 1 << variantListIndex;
- uint32_t varMask = targets->geti(target);
- targets->puti(target, varMask | addMask, status);
+ uint32_t addMask = 1 << variantListIndex;
+ uint32_t varMask = targets->geti(target);
+ targets->puti(target, varMask | addMask, status);
}
/**
@@ -1014,24 +1014,24 @@ void TransliteratorRegistry::removeSTV(const UnicodeString& source,
const UnicodeString& variant) {
// assert(source.length() > 0);
// assert(target.length() > 0);
- UErrorCode status = U_ZERO_ERROR;
+ UErrorCode status = U_ZERO_ERROR;
Hashtable *targets = (Hashtable*) specDAG.get(source);
- if (targets == NULL) {
+ if (targets == NULL) {
return; // should never happen for valid s-t/v
}
- uint32_t varMask = targets->geti(target);
- if (varMask == 0) {
+ uint32_t varMask = targets->geti(target);
+ if (varMask == 0) {
return; // should never happen for valid s-t/v
}
- int32_t variantListIndex = variantList.indexOf((void*) &variant, 0);
- if (variantListIndex < 0) {
- return; // should never happen for valid s-t/v
- }
- int32_t remMask = 1 << variantListIndex;
- varMask &= (~remMask);
- if (varMask != 0) {
- targets->puti(target, varMask, status);
- } else {
+ int32_t variantListIndex = variantList.indexOf((void*) &variant, 0);
+ if (variantListIndex < 0) {
+ return; // should never happen for valid s-t/v
+ }
+ int32_t remMask = 1 << variantListIndex;
+ varMask &= (~remMask);
+ if (varMask != 0) {
+ targets->puti(target, varMask, status);
+ } else {
targets->remove(target); // should delete variants
if (targets->count() == 0) {
specDAG.remove(source); // should delete targets
@@ -1323,18 +1323,18 @@ Transliterator* TransliteratorRegistry::instantiateEntry(const UnicodeString& ID
UVector* rbts = new UVector(entry->u.dataVector->size(), status);
// Check for null pointer
if (rbts == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
}
int32_t passNumber = 1;
for (int32_t i = 0; U_SUCCESS(status) && i < entry->u.dataVector->size(); i++) {
// TODO: Should passNumber be turned into a decimal-string representation (1 -> "1")?
- Transliterator* tl = new RuleBasedTransliterator(UnicodeString(CompoundTransliterator::PASS_STRING) + UnicodeString(passNumber++),
+ Transliterator* tl = new RuleBasedTransliterator(UnicodeString(CompoundTransliterator::PASS_STRING) + UnicodeString(passNumber++),
(TransliterationRuleData*)(entry->u.dataVector->elementAt(i)), FALSE);
- if (tl == 0)
+ if (tl == 0)
status = U_MEMORY_ALLOCATION_ERROR;
else
- rbts->addElement(tl, status);
+ rbts->addElement(tl, status);
}
if (U_FAILURE(status)) {
delete rbts;
@@ -1395,7 +1395,7 @@ Transliterator* TransliteratorRegistry::instantiateEntry(const UnicodeString& ID
}
return 0;
default:
- UPRV_UNREACHABLE; // can't get here
+ UPRV_UNREACHABLE; // can't get here
}
}
U_NAMESPACE_END
diff --git a/contrib/libs/icu/i18n/transreg.h b/contrib/libs/icu/i18n/transreg.h
index 041244e1b0..a90a8f6848 100644
--- a/contrib/libs/icu/i18n/transreg.h
+++ b/contrib/libs/icu/i18n/transreg.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -440,16 +440,16 @@ class TransliteratorRegistry : public UMemory {
/**
* DAG of visible IDs by spec. Hashtable: source => (Hashtable:
- * target => variant bitmask)
+ * target => variant bitmask)
*/
Hashtable specDAG;
/**
- * Vector of all variant names
- */
- UVector variantList;
-
- /**
+ * Vector of all variant names
+ */
+ UVector variantList;
+
+ /**
* Vector of public full IDs.
*/
UVector availableIDs;
diff --git a/contrib/libs/icu/i18n/tridpars.cpp b/contrib/libs/icu/i18n/tridpars.cpp
index 65bfc88063..daa75fcb71 100644
--- a/contrib/libs/icu/i18n/tridpars.cpp
+++ b/contrib/libs/icu/i18n/tridpars.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -50,7 +50,7 @@ static UInitOnce gSpecialInversesInitOnce = U_INITONCE_INITIALIZER;
/**
* The mutex controlling access to SPECIAL_INVERSES
*/
-static UMutex LOCK;
+static UMutex LOCK;
TransliteratorIDParser::Specs::Specs(const UnicodeString& s, const UnicodeString& t,
const UnicodeString& v, UBool sawS,
@@ -294,7 +294,7 @@ UnicodeSet* TransliteratorIDParser::parseGlobalFilter(const UnicodeString& id, i
pos = ppos.getIndex();
if (withParens == 1 && !ICU_Utility::parseChar(id, pos, CLOSE_REV)) {
- delete filter;
+ delete filter;
pos = start;
return NULL;
}
diff --git a/contrib/libs/icu/i18n/tridpars.h b/contrib/libs/icu/i18n/tridpars.h
index 5e42f068a4..1a87a808ae 100644
--- a/contrib/libs/icu/i18n/tridpars.h
+++ b/contrib/libs/icu/i18n/tridpars.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**************************************************************************
diff --git a/contrib/libs/icu/i18n/tzfmt.cpp b/contrib/libs/icu/i18n/tzfmt.cpp
index f87f0f67b1..62faa96eaa 100644
--- a/contrib/libs/icu/i18n/tzfmt.cpp
+++ b/contrib/libs/icu/i18n/tzfmt.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -14,27 +14,27 @@
#include "unicode/calendar.h"
#include "unicode/tzfmt.h"
#include "unicode/numsys.h"
-#include "unicode/strenum.h"
+#include "unicode/strenum.h"
#include "unicode/uchar.h"
#include "unicode/udat.h"
-#include "unicode/ustring.h"
-#include "unicode/utf16.h"
-#include "bytesinkutil.h"
-#include "charstr.h"
+#include "unicode/ustring.h"
+#include "unicode/utf16.h"
+#include "bytesinkutil.h"
+#include "charstr.h"
#include "tzgnames.h"
#include "cmemory.h"
#include "cstring.h"
#include "putilimp.h"
#include "uassert.h"
#include "ucln_in.h"
-#include "ulocimp.h"
+#include "ulocimp.h"
#include "umutex.h"
#include "uresimp.h"
#include "ureslocs.h"
#include "uvector.h"
#include "zonemeta.h"
#include "tznames_impl.h" // TextTrieMap
-#include "patternprops.h"
+#include "patternprops.h"
U_NAMESPACE_BEGIN
@@ -150,7 +150,7 @@ static icu::UInitOnce gZoneIdTrieInitOnce = U_INITONCE_INITIALIZER;
static TextTrieMap *gShortZoneIdTrie = NULL;
static icu::UInitOnce gShortZoneIdTrieInitOnce = U_INITONCE_INITIALIZER;
-static UMutex gLock;
+static UMutex gLock;
U_CDECL_BEGIN
/**
@@ -270,7 +270,7 @@ GMTOffsetField::isValid(FieldType type, int32_t width) {
case SECOND:
return (width == 2);
default:
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
return (width > 0);
}
@@ -325,15 +325,15 @@ TimeZoneFormat::TimeZoneFormat(const Locale& locale, UErrorCode& status)
}
const char* region = fLocale.getCountry();
- int32_t regionLen = static_cast<int32_t>(uprv_strlen(region));
+ int32_t regionLen = static_cast<int32_t>(uprv_strlen(region));
if (regionLen == 0) {
- CharString loc;
- {
- CharStringByteSink sink(&loc);
- ulocimp_addLikelySubtags(fLocale.getName(), sink, &status);
- }
+ CharString loc;
+ {
+ CharStringByteSink sink(&loc);
+ ulocimp_addLikelySubtags(fLocale.getName(), sink, &status);
+ }
- regionLen = uloc_getCountry(loc.data(), fTargetRegion, sizeof(fTargetRegion), &status);
+ regionLen = uloc_getCountry(loc.data(), fTargetRegion, sizeof(fTargetRegion), &status);
if (U_SUCCESS(status)) {
fTargetRegion[regionLen] = 0;
} else {
@@ -505,7 +505,7 @@ TimeZoneFormat::operator==(const Format& other) const {
return isEqual;
}
-TimeZoneFormat*
+TimeZoneFormat*
TimeZoneFormat::clone() const {
return new TimeZoneFormat(*this);
}
@@ -595,7 +595,7 @@ TimeZoneFormat::setGMTOffsetPattern(UTimeZoneFormatGMTOffsetPatternType type, co
required = FIELDS_HMS;
break;
default:
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
UVector* patternItems = parseOffsetPattern(pattern, required, status);
@@ -795,7 +795,7 @@ TimeZoneFormat::format(const Formattable& obj, UnicodeString& appendTo,
if (tz != NULL) {
int32_t rawOffset, dstOffset;
tz->getOffset(date, FALSE, rawOffset, dstOffset, status);
- UChar buf[ZONE_NAME_U16_MAX];
+ UChar buf[ZONE_NAME_U16_MAX];
UnicodeString result(buf, 0, UPRV_LENGTHOF(buf));
formatOffsetLocalizedGMT(rawOffset + dstOffset, result, status);
if (U_SUCCESS(status)) {
@@ -1033,7 +1033,7 @@ TimeZoneFormat::parse(UTimeZoneFormatStyle style, const UnicodeString& text, Par
break;
default:
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
int32_t len = 0;
@@ -1421,7 +1421,7 @@ TimeZoneFormat::getTZDBTimeZoneNames(UErrorCode& status) const {
UnicodeString&
TimeZoneFormat::formatExemplarLocation(const TimeZone& tz, UnicodeString& name) const {
- UChar locationBuf[ZONE_NAME_U16_MAX];
+ UChar locationBuf[ZONE_NAME_U16_MAX];
UnicodeString location(locationBuf, 0, UPRV_LENGTHOF(locationBuf));
const UChar* canonicalID = ZoneMeta::getCanonicalCLDRID(tz);
@@ -1819,9 +1819,9 @@ TimeZoneFormat::parseOffsetFields(const UnicodeString& text, int32_t start, UBoo
// but it should be parsed as 00:10:20.
int32_t tmpLen = 0;
int32_t tmpSign = 1;
- int32_t tmpH = 0;
- int32_t tmpM = 0;
- int32_t tmpS = 0;
+ int32_t tmpH = 0;
+ int32_t tmpM = 0;
+ int32_t tmpS = 0;
for (int32_t patidx = 0; PARSE_GMT_OFFSET_TYPES[patidx] >= 0; patidx++) {
int32_t gmtPatType = PARSE_GMT_OFFSET_TYPES[patidx];
@@ -1869,27 +1869,27 @@ TimeZoneFormat::parseOffsetFieldsWithPattern(const UnicodeString& text, int32_t
if (fieldType == GMTOffsetField::TEXT) {
const UChar* patStr = field->getPatternText();
len = u_strlen(patStr);
- if (i == 0) {
- // When TimeZoneFormat parse() is called from SimpleDateFormat,
- // leading space characters might be truncated. If the first pattern text
- // starts with such character (e.g. Bidi control), then we need to
- // skip the leading space charcters.
- if (idx < text.length() && !PatternProps::isWhiteSpace(text.char32At(idx))) {
- while (len > 0) {
- UChar32 ch;
- int32_t chLen;
- U16_GET(patStr, 0, 0, len, ch);
- if (PatternProps::isWhiteSpace(ch)) {
- chLen = U16_LENGTH(ch);
- len -= chLen;
- patStr += chLen;
- }
- else {
- break;
- }
- }
- }
- }
+ if (i == 0) {
+ // When TimeZoneFormat parse() is called from SimpleDateFormat,
+ // leading space characters might be truncated. If the first pattern text
+ // starts with such character (e.g. Bidi control), then we need to
+ // skip the leading space charcters.
+ if (idx < text.length() && !PatternProps::isWhiteSpace(text.char32At(idx))) {
+ while (len > 0) {
+ UChar32 ch;
+ int32_t chLen;
+ U16_GET(patStr, 0, 0, len, ch);
+ if (PatternProps::isWhiteSpace(ch)) {
+ chLen = U16_LENGTH(ch);
+ len -= chLen;
+ patStr += chLen;
+ }
+ else {
+ break;
+ }
+ }
+ }
+ }
if (text.caseCompare(idx, len, patStr, 0) != 0) {
failed = TRUE;
break;
@@ -2458,7 +2458,7 @@ TimeZoneFormat::parseOffsetPattern(const UnicodeString& pattern, OffsetFields re
isPrevQuote = TRUE;
if (itemType != GMTOffsetField::TEXT) {
if (GMTOffsetField::isValid(itemType, itemLength)) {
- GMTOffsetField* fld = GMTOffsetField::createTimeField(itemType, static_cast<uint8_t>(itemLength), status);
+ GMTOffsetField* fld = GMTOffsetField::createTimeField(itemType, static_cast<uint8_t>(itemLength), status);
result->addElement(fld, status);
if (U_FAILURE(status)) {
break;
@@ -2493,7 +2493,7 @@ TimeZoneFormat::parseOffsetPattern(const UnicodeString& pattern, OffsetFields re
}
} else {
if (GMTOffsetField::isValid(itemType, itemLength)) {
- GMTOffsetField* fld = GMTOffsetField::createTimeField(itemType, static_cast<uint8_t>(itemLength), status);
+ GMTOffsetField* fld = GMTOffsetField::createTimeField(itemType, static_cast<uint8_t>(itemLength), status);
result->addElement(fld, status);
if (U_FAILURE(status)) {
break;
@@ -2511,7 +2511,7 @@ TimeZoneFormat::parseOffsetPattern(const UnicodeString& pattern, OffsetFields re
// a string literal
if (itemType != GMTOffsetField::TEXT) {
if (GMTOffsetField::isValid(itemType, itemLength)) {
- GMTOffsetField* fld = GMTOffsetField::createTimeField(itemType, static_cast<uint8_t>(itemLength), status);
+ GMTOffsetField* fld = GMTOffsetField::createTimeField(itemType, static_cast<uint8_t>(itemLength), status);
result->addElement(fld, status);
if (U_FAILURE(status)) {
break;
@@ -2536,7 +2536,7 @@ TimeZoneFormat::parseOffsetPattern(const UnicodeString& pattern, OffsetFields re
}
} else {
if (GMTOffsetField::isValid(itemType, itemLength)) {
- GMTOffsetField* fld = GMTOffsetField::createTimeField(itemType, static_cast<uint8_t>(itemLength), status);
+ GMTOffsetField* fld = GMTOffsetField::createTimeField(itemType, static_cast<uint8_t>(itemLength), status);
result->addElement(fld, status);
} else {
status = U_ILLEGAL_ARGUMENT_ERROR;
@@ -2653,12 +2653,12 @@ TimeZoneFormat::checkAbuttingHoursAndMinutes() {
UVector *items = fGMTOffsetPatternItems[type];
for (int32_t i = 0; i < items->size(); i++) {
const GMTOffsetField* item = (GMTOffsetField*)items->elementAt(i);
- GMTOffsetField::FieldType fieldType = item->getType();
- if (fieldType != GMTOffsetField::TEXT) {
+ GMTOffsetField::FieldType fieldType = item->getType();
+ if (fieldType != GMTOffsetField::TEXT) {
if (afterH) {
fAbuttingOffsetHoursAndMinutes = TRUE;
break;
- } else if (fieldType == GMTOffsetField::HOUR) {
+ } else if (fieldType == GMTOffsetField::HOUR) {
afterH = TRUE;
}
} else if (afterH) {
@@ -2782,7 +2782,7 @@ static void U_CALLCONV initZoneIdTrie(UErrorCode &status) {
}
StringEnumeration *tzenum = TimeZone::createEnumeration();
const UnicodeString *id;
- while ((id = tzenum->snext(status)) != NULL) {
+ while ((id = tzenum->snext(status)) != NULL) {
const UChar* uid = ZoneMeta::findTimeZoneID(*id);
if (uid) {
gZoneIdTrie->put(uid, const_cast<UChar *>(uid), status);
@@ -2829,7 +2829,7 @@ static void U_CALLCONV initShortZoneIdTrie(UErrorCode &status) {
status = U_MEMORY_ALLOCATION_ERROR;
} else {
const UnicodeString *id;
- while ((id = tzenum->snext(status)) != NULL) {
+ while ((id = tzenum->snext(status)) != NULL) {
const UChar* uID = ZoneMeta::findTimeZoneID(*id);
const UChar* shortID = ZoneMeta::getShortID(*id);
if (shortID && uID) {
diff --git a/contrib/libs/icu/i18n/tzgnames.cpp b/contrib/libs/icu/i18n/tzgnames.cpp
index e056461dc3..94d00d7e8d 100644
--- a/contrib/libs/icu/i18n/tzgnames.cpp
+++ b/contrib/libs/icu/i18n/tzgnames.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -18,18 +18,18 @@
#include "unicode/rbtz.h"
#include "unicode/simpleformatter.h"
#include "unicode/simpletz.h"
-#include "unicode/strenum.h"
+#include "unicode/strenum.h"
#include "unicode/vtzone.h"
-#include "bytesinkutil.h"
-#include "charstr.h"
+#include "bytesinkutil.h"
+#include "charstr.h"
#include "cmemory.h"
#include "cstring.h"
#include "mutex.h"
#include "uhash.h"
#include "uassert.h"
#include "umutex.h"
-#include "ulocimp.h"
+#include "ulocimp.h"
#include "uresimp.h"
#include "ureslocs.h"
#include "zonemeta.h"
@@ -272,7 +272,7 @@ GNameSearchHandler::getMatches(int32_t& maxMatchLen) {
return results;
}
-static UMutex gLock;
+static UMutex gLock;
class TZGNCore : public UMemory {
public:
@@ -410,15 +410,15 @@ TZGNCore::initialize(const Locale& locale, UErrorCode& status) {
// target region
const char* region = fLocale.getCountry();
- int32_t regionLen = static_cast<int32_t>(uprv_strlen(region));
+ int32_t regionLen = static_cast<int32_t>(uprv_strlen(region));
if (regionLen == 0) {
- CharString loc;
- {
- CharStringByteSink sink(&loc);
- ulocimp_addLikelySubtags(fLocale.getName(), sink, &status);
- }
+ CharString loc;
+ {
+ CharStringByteSink sink(&loc);
+ ulocimp_addLikelySubtags(fLocale.getName(), sink, &status);
+ }
- regionLen = uloc_getCountry(loc.data(), fTargetRegion, sizeof(fTargetRegion), &status);
+ regionLen = uloc_getCountry(loc.data(), fTargetRegion, sizeof(fTargetRegion), &status);
if (U_SUCCESS(status)) {
fTargetRegion[regionLen] = 0;
} else {
@@ -621,7 +621,7 @@ TZGNCore::formatGenericNonLocationName(const TimeZone& tz, UTimeZoneGenericNameT
UErrorCode status = U_ZERO_ERROR;
UBool useStandard = FALSE;
int32_t raw, sav;
- UChar tmpNameBuf[ZONE_NAME_U16_MAX];
+ UChar tmpNameBuf[ZONE_NAME_U16_MAX];
tz.getOffset(date, FALSE, raw, sav, status);
if (U_FAILURE(status)) {
@@ -689,7 +689,7 @@ TZGNCore::formatGenericNonLocationName(const TimeZone& tz, UTimeZoneGenericNameT
// for some meta zones in some locales. This looks like a data bugs.
// For now, we check if the standard name is different from its generic
// name below.
- UChar genNameBuf[ZONE_NAME_U16_MAX];
+ UChar genNameBuf[ZONE_NAME_U16_MAX];
UnicodeString mzGenericName(genNameBuf, 0, UPRV_LENGTHOF(genNameBuf));
fTimeZoneNames->getMetaZoneDisplayName(mzID, nameType, mzGenericName);
if (stdName.caseCompare(mzGenericName, 0) == 0) {
@@ -862,7 +862,7 @@ TZGNCore::loadStrings(const UnicodeString& tzCanonicalID) {
};
StringEnumeration *mzIDs = fTimeZoneNames->getAvailableMetaZoneIDs(tzCanonicalID, status);
- while ((mzID = mzIDs->snext(status)) != NULL) {
+ while ((mzID = mzIDs->snext(status)) != NULL) {
if (U_FAILURE(status)) {
break;
}
@@ -1050,7 +1050,7 @@ TZGNCore::findLocal(const UnicodeString& text, int32_t start, uint32_t types, UE
StringEnumeration *tzIDs = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL, NULL, NULL, status);
if (U_SUCCESS(status)) {
const UnicodeString *tzID;
- while ((tzID = tzIDs->snext(status)) != NULL) {
+ while ((tzID = tzIDs->snext(status)) != NULL) {
if (U_FAILURE(status)) {
break;
}
@@ -1118,7 +1118,7 @@ typedef struct TZGNCoreRef {
} TZGNCoreRef;
// TZGNCore object cache handling
-static UMutex gTZGNLock;
+static UMutex gTZGNLock;
static UHashtable *gTZGNCoreCache = NULL;
static UBool gTZGNCoreCacheInitialized = FALSE;
@@ -1170,7 +1170,7 @@ static void sweepCache() {
const UHashElement* elem;
double now = (double)uprv_getUTCtime();
- while ((elem = uhash_nextElement(gTZGNCoreCache, &pos)) != NULL) {
+ while ((elem = uhash_nextElement(gTZGNCoreCache, &pos)) != NULL) {
TZGNCoreRef *entry = (TZGNCoreRef *)elem->value.pointer;
if (entry->refCount <= 0 && (now - entry->lastAccess) > CACHE_EXPIRATION) {
// delete this entry
diff --git a/contrib/libs/icu/i18n/tzgnames.h b/contrib/libs/icu/i18n/tzgnames.h
index 71d9d84dc0..ccfb253659 100644
--- a/contrib/libs/icu/i18n/tzgnames.h
+++ b/contrib/libs/icu/i18n/tzgnames.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -46,7 +46,7 @@ public:
static TimeZoneGenericNames* createInstance(const Locale& locale, UErrorCode& status);
virtual UBool operator==(const TimeZoneGenericNames& other) const;
- virtual UBool operator!=(const TimeZoneGenericNames& other) const {return !operator==(other);}
+ virtual UBool operator!=(const TimeZoneGenericNames& other) const {return !operator==(other);}
virtual TimeZoneGenericNames* clone() const;
UnicodeString& getDisplayName(const TimeZone& tz, UTimeZoneGenericNameType type,
diff --git a/contrib/libs/icu/i18n/tznames.cpp b/contrib/libs/icu/i18n/tznames.cpp
index d789c12363..4e18d1b4a9 100644
--- a/contrib/libs/icu/i18n/tznames.cpp
+++ b/contrib/libs/icu/i18n/tznames.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -29,7 +29,7 @@
U_NAMESPACE_BEGIN
// TimeZoneNames object cache handling
-static UMutex gTimeZoneNamesLock;
+static UMutex gTimeZoneNamesLock;
static UHashtable *gTimeZoneNamesCache = NULL;
static UBool gTimeZoneNamesCacheInitialized = FALSE;
@@ -87,7 +87,7 @@ static void sweepCache() {
const UHashElement* elem;
double now = (double)uprv_getUTCtime();
- while ((elem = uhash_nextElement(gTimeZoneNamesCache, &pos)) != 0) {
+ while ((elem = uhash_nextElement(gTimeZoneNamesCache, &pos)) != 0) {
TimeZoneNamesCacheEntry *entry = (TimeZoneNamesCacheEntry *)elem->value.pointer;
if (entry->refCount <= 0 && (now - entry->lastAccess) > CACHE_EXPIRATION) {
// delete this entry
@@ -105,8 +105,8 @@ public:
virtual ~TimeZoneNamesDelegate();
virtual UBool operator==(const TimeZoneNames& other) const;
- virtual UBool operator!=(const TimeZoneNames& other) const {return !operator==(other);}
- virtual TimeZoneNamesDelegate* clone() const;
+ virtual UBool operator!=(const TimeZoneNames& other) const {return !operator==(other);}
+ virtual TimeZoneNamesDelegate* clone() const;
StringEnumeration* getAvailableMetaZoneIDs(UErrorCode& status) const;
StringEnumeration* getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const;
@@ -233,7 +233,7 @@ TimeZoneNamesDelegate::operator==(const TimeZoneNames& other) const {
return FALSE;
}
-TimeZoneNamesDelegate*
+TimeZoneNamesDelegate*
TimeZoneNamesDelegate::clone() const {
TimeZoneNamesDelegate* other = new TimeZoneNamesDelegate();
if (other != NULL) {
diff --git a/contrib/libs/icu/i18n/tznames_impl.cpp b/contrib/libs/icu/i18n/tznames_impl.cpp
index 186aaaf74d..258f104506 100644
--- a/contrib/libs/icu/i18n/tznames_impl.cpp
+++ b/contrib/libs/icu/i18n/tznames_impl.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -15,20 +15,20 @@
#if !UCONFIG_NO_FORMATTING
-#include "unicode/strenum.h"
+#include "unicode/strenum.h"
#include "unicode/ustring.h"
#include "unicode/timezone.h"
-#include "unicode/utf16.h"
+#include "unicode/utf16.h"
#include "tznames_impl.h"
-#include "bytesinkutil.h"
-#include "charstr.h"
+#include "bytesinkutil.h"
+#include "charstr.h"
#include "cmemory.h"
#include "cstring.h"
#include "uassert.h"
#include "mutex.h"
#include "resource.h"
-#include "ulocimp.h"
+#include "ulocimp.h"
#include "uresimp.h"
#include "ureslocs.h"
#include "zonemeta.h"
@@ -52,7 +52,7 @@ static const UChar NO_NAME[] = { 0 }; // for empty no-fallback time
static const char* TZDBNAMES_KEYS[] = {"ss", "sd"};
static const int32_t TZDBNAMES_KEYS_SIZE = UPRV_LENGTHOF(TZDBNAMES_KEYS);
-static UMutex gDataMutex;
+static UMutex gDataMutex;
static UHashtable* gTZDBNamesMap = NULL;
static icu::UInitOnce gTZDBNamesMapInitOnce = U_INITONCE_INITIALIZER;
@@ -72,7 +72,7 @@ enum UTimeZoneNameTypeIndex {
UTZNM_INDEX_SHORT_DAYLIGHT,
UTZNM_INDEX_COUNT
};
-static const UChar* const EMPTY_NAMES[UTZNM_INDEX_COUNT] = {0,0,0,0,0,0,0};
+static const UChar* const EMPTY_NAMES[UTZNM_INDEX_COUNT] = {0,0,0,0,0,0,0};
U_CDECL_BEGIN
static UBool U_CALLCONV tzdbTimeZoneNames_cleanup(void) {
@@ -386,10 +386,10 @@ TextTrieMap::search(const UnicodeString &text, int32_t start,
// the ICU atomic safe functions for assigning and testing.
// Don't test the pointer fLazyContents.
// Don't do unless it's really required.
-
- // Mutex for protecting the lazy creation of the Trie node structure on the first call to search().
- static UMutex TextTrieMutex;
-
+
+ // Mutex for protecting the lazy creation of the Trie node structure on the first call to search().
+ static UMutex TextTrieMutex;
+
Mutex lock(&TextTrieMutex);
if (fLazyContents != NULL) {
TextTrieMap *nonConstThis = const_cast<TextTrieMap *>(this);
@@ -417,28 +417,28 @@ TextTrieMap::search(CharacterNode *node, const UnicodeString &text, int32_t star
}
}
if (fIgnoreCase) {
- // for folding we need to get a complete code point.
- // size of character may grow after fold operation;
- // then we need to get result as UTF16 code units.
- UChar32 c32 = text.char32At(index);
- index += U16_LENGTH(c32);
- UnicodeString tmp(c32);
+ // for folding we need to get a complete code point.
+ // size of character may grow after fold operation;
+ // then we need to get result as UTF16 code units.
+ UChar32 c32 = text.char32At(index);
+ index += U16_LENGTH(c32);
+ UnicodeString tmp(c32);
tmp.foldCase();
int32_t tmpidx = 0;
while (tmpidx < tmp.length()) {
- UChar c = tmp.charAt(tmpidx++);
+ UChar c = tmp.charAt(tmpidx++);
node = getChildNode(node, c);
if (node == NULL) {
break;
}
}
} else {
- // here we just get the next UTF16 code unit
- UChar c = text.charAt(index++);
+ // here we just get the next UTF16 code unit
+ UChar c = text.charAt(index++);
node = getChildNode(node, c);
}
if (node != NULL) {
- search(node, text, start, index, handler, status);
+ search(node, text, start, index, handler, status);
}
}
@@ -1079,7 +1079,7 @@ TimeZoneNamesImpl::loadStrings(const UnicodeString& tzCanonicalID, UErrorCode& s
U_ASSERT(!mzIDs.isNull());
const UnicodeString *mzID;
- while (((mzID = mzIDs->snext(status)) != NULL) && U_SUCCESS(status)) {
+ while (((mzID = mzIDs->snext(status)) != NULL) && U_SUCCESS(status)) {
loadMetaZoneNames(*mzID, status);
}
}
@@ -1113,7 +1113,7 @@ TimeZoneNamesImpl::operator==(const TimeZoneNames& other) const {
return FALSE;
}
-TimeZoneNamesImpl*
+TimeZoneNamesImpl*
TimeZoneNamesImpl::clone() const {
UErrorCode status = U_ZERO_ERROR;
return new TimeZoneNamesImpl(fLocale, status);
@@ -1289,7 +1289,7 @@ static void mergeTimeZoneKey(const UnicodeString& mzID, char* result) {
char mzIdChar[ZID_KEY_MAX + 1];
int32_t keyLen;
- int32_t prefixLen = static_cast<int32_t>(uprv_strlen(gMZPrefix));
+ int32_t prefixLen = static_cast<int32_t>(uprv_strlen(gMZPrefix));
keyLen = mzID.extract(0, mzID.length(), mzIdChar, ZID_KEY_MAX + 1, US_INV);
uprv_memcpy((void *)result, (void *)gMZPrefix, prefixLen);
uprv_memcpy((void *)(result + prefixLen), (void *)mzIdChar, keyLen);
@@ -1457,7 +1457,7 @@ struct TimeZoneNamesImpl::ZoneStringsLoader : public ResourceSink {
virtual ~ZoneStringsLoader();
void* createKey(const char* key, UErrorCode& status) {
- int32_t len = sizeof(char) * (static_cast<int32_t>(uprv_strlen(key)) + 1);
+ int32_t len = sizeof(char) * (static_cast<int32_t>(uprv_strlen(key)) + 1);
char* newKey = (char*) uprv_malloc(len);
if (newKey == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
@@ -1473,7 +1473,7 @@ struct TimeZoneNamesImpl::ZoneStringsLoader : public ResourceSink {
}
UnicodeString mzIDFromKey(const char* key) {
- return UnicodeString(key + MZ_PREFIX_LEN, static_cast<int32_t>(uprv_strlen(key)) - MZ_PREFIX_LEN, US_INV);
+ return UnicodeString(key + MZ_PREFIX_LEN, static_cast<int32_t>(uprv_strlen(key)) - MZ_PREFIX_LEN, US_INV);
}
UnicodeString tzIDFromKey(const char* key) {
@@ -1660,7 +1660,7 @@ void TimeZoneNamesImpl::internalLoadAllDisplayNames(UErrorCode& status) {
StringEnumeration *tzIDs = TimeZone::createTimeZoneIDEnumeration(
UCAL_ZONE_TYPE_CANONICAL, NULL, NULL, status);
if (U_SUCCESS(status)) {
- while ((id = tzIDs->snext(status)) != NULL) {
+ while ((id = tzIDs->snext(status)) != NULL) {
if (U_FAILURE(status)) {
break;
}
@@ -1948,8 +1948,8 @@ TZDBNameSearchHandler::handleMatch(int32_t matchLength, const CharacterNode *nod
// metazone mapping for "CST" is America_Central,
// but if region is one of CN/MO/TW, "CST" is parsed
// as metazone China (China Standard Time).
- for (int32_t j = 0; j < ninfo->nRegions; j++) {
- const char *region = ninfo->parseRegions[j];
+ for (int32_t j = 0; j < ninfo->nRegions; j++) {
+ const char *region = ninfo->parseRegions[j];
if (uprv_strcmp(fRegion, region) == 0) {
match = ninfo;
matchRegion = TRUE;
@@ -2063,11 +2063,11 @@ static void U_CALLCONV prepareFind(UErrorCode &status) {
const UnicodeString *mzID;
StringEnumeration *mzIDs = TimeZoneNamesImpl::_getAvailableMetaZoneIDs(status);
if (U_SUCCESS(status)) {
- while ((mzID = mzIDs->snext(status)) != 0 && U_SUCCESS(status)) {
+ while ((mzID = mzIDs->snext(status)) != 0 && U_SUCCESS(status)) {
const TZDBNames *names = TZDBTimeZoneNames::getMetaZoneNames(*mzID, status);
- if (U_FAILURE(status)) {
- break;
- }
+ if (U_FAILURE(status)) {
+ break;
+ }
if (names == NULL) {
continue;
}
@@ -2132,15 +2132,15 @@ TZDBTimeZoneNames::TZDBTimeZoneNames(const Locale& locale)
: fLocale(locale) {
UBool useWorld = TRUE;
const char* region = fLocale.getCountry();
- int32_t regionLen = static_cast<int32_t>(uprv_strlen(region));
+ int32_t regionLen = static_cast<int32_t>(uprv_strlen(region));
if (regionLen == 0) {
UErrorCode status = U_ZERO_ERROR;
- CharString loc;
- {
- CharStringByteSink sink(&loc);
- ulocimp_addLikelySubtags(fLocale.getName(), sink, &status);
- }
- regionLen = uloc_getCountry(loc.data(), fRegion, sizeof(fRegion), &status);
+ CharString loc;
+ {
+ CharStringByteSink sink(&loc);
+ ulocimp_addLikelySubtags(fLocale.getName(), sink, &status);
+ }
+ regionLen = uloc_getCountry(loc.data(), fRegion, sizeof(fRegion), &status);
if (U_SUCCESS(status) && regionLen < (int32_t)sizeof(fRegion)) {
useWorld = FALSE;
}
@@ -2165,7 +2165,7 @@ TZDBTimeZoneNames::operator==(const TimeZoneNames& other) const {
return FALSE;
}
-TZDBTimeZoneNames*
+TZDBTimeZoneNames*
TZDBTimeZoneNames::clone() const {
return new TZDBTimeZoneNames(fLocale);
}
@@ -2202,11 +2202,11 @@ TZDBTimeZoneNames::getMetaZoneDisplayName(const UnicodeString& mzID,
UErrorCode status = U_ZERO_ERROR;
const TZDBNames *tzdbNames = TZDBTimeZoneNames::getMetaZoneNames(mzID, status);
if (U_SUCCESS(status)) {
- if (tzdbNames != NULL) {
- const UChar *s = tzdbNames->getName(type);
- if (s != NULL) {
- name.setTo(TRUE, s, -1);
- }
+ if (tzdbNames != NULL) {
+ const UChar *s = tzdbNames->getName(type);
+ if (s != NULL) {
+ name.setTo(TRUE, s, -1);
+ }
}
}
@@ -2250,7 +2250,7 @@ TZDBTimeZoneNames::getMetaZoneNames(const UnicodeString& mzID, UErrorCode& statu
U_ASSERT(status == U_ZERO_ERROR); // already checked length above
mzIDKey[mzID.length()] = 0;
- static UMutex gTZDBNamesMapLock;
+ static UMutex gTZDBNamesMapLock;
umtx_lock(&gTZDBNamesMapLock);
{
void *cacheVal = uhash_get(gTZDBNamesMap, mzIDKey);
diff --git a/contrib/libs/icu/i18n/tznames_impl.h b/contrib/libs/icu/i18n/tznames_impl.h
index 1286eeb80d..2fdfa91667 100644
--- a/contrib/libs/icu/i18n/tznames_impl.h
+++ b/contrib/libs/icu/i18n/tznames_impl.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -27,9 +27,9 @@
#include "uvector.h"
#include "umutex.h"
-// Some zone display names involving supplementary characters can be over 50 chars, 100 UTF-16 code units, 200 UTF-8 bytes
-#define ZONE_NAME_U16_MAX 128
-
+// Some zone display names involving supplementary characters can be over 50 chars, 100 UTF-16 code units, 200 UTF-8 bytes
+#define ZONE_NAME_U16_MAX 128
+
U_NAMESPACE_BEGIN
/*
@@ -174,7 +174,7 @@ public:
virtual ~TimeZoneNamesImpl();
virtual UBool operator==(const TimeZoneNames& other) const;
- virtual TimeZoneNamesImpl* clone() const;
+ virtual TimeZoneNamesImpl* clone() const;
StringEnumeration* getAvailableMetaZoneIDs(UErrorCode& status) const;
StringEnumeration* getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const;
@@ -236,7 +236,7 @@ public:
virtual ~TZDBTimeZoneNames();
virtual UBool operator==(const TimeZoneNames& other) const;
- virtual TZDBTimeZoneNames* clone() const;
+ virtual TZDBTimeZoneNames* clone() const;
StringEnumeration* getAvailableMetaZoneIDs(UErrorCode& status) const;
StringEnumeration* getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const;
@@ -249,8 +249,8 @@ public:
TimeZoneNames::MatchInfoCollection* find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const;
- // When TZDBNames for the metazone is not available, this method returns NULL,
- // but does NOT set U_MISSING_RESOURCE_ERROR to status.
+ // When TZDBNames for the metazone is not available, this method returns NULL,
+ // but does NOT set U_MISSING_RESOURCE_ERROR to status.
static const TZDBNames* getMetaZoneNames(const UnicodeString& mzId, UErrorCode& status);
private:
diff --git a/contrib/libs/icu/i18n/tzrule.cpp b/contrib/libs/icu/i18n/tzrule.cpp
index 759a2d4c67..239b3b0725 100644
--- a/contrib/libs/icu/i18n/tzrule.cpp
+++ b/contrib/libs/icu/i18n/tzrule.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -108,7 +108,7 @@ InitialTimeZoneRule::~InitialTimeZoneRule() {
}
InitialTimeZoneRule*
-InitialTimeZoneRule::clone() const {
+InitialTimeZoneRule::clone() const {
return new InitialTimeZoneRule(*this);
}
diff --git a/contrib/libs/icu/i18n/tztrans.cpp b/contrib/libs/icu/i18n/tztrans.cpp
index 3199b78ea8..eee98251d3 100644
--- a/contrib/libs/icu/i18n/tztrans.cpp
+++ b/contrib/libs/icu/i18n/tztrans.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/ucal.cpp b/contrib/libs/icu/i18n/ucal.cpp
index 67c51aea27..c5db70c785 100644
--- a/contrib/libs/icu/i18n/ucal.cpp
+++ b/contrib/libs/icu/i18n/ucal.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -34,7 +34,7 @@ U_NAMESPACE_USE
static TimeZone*
_createTimeZone(const UChar* zoneID, int32_t len, UErrorCode* ec) {
TimeZone* zone = NULL;
- if (ec != NULL && U_SUCCESS(*ec)) {
+ if (ec != NULL && U_SUCCESS(*ec)) {
// Note that if zoneID is invalid, we get back GMT. This odd
// behavior is by design and goes back to the JDK. The only
// failure we will see is a memory allocation failure.
@@ -69,7 +69,7 @@ ucal_openCountryTimeZones(const char* country, UErrorCode* ec) {
U_CAPI int32_t U_EXPORT2
ucal_getDefaultTimeZone(UChar* result, int32_t resultCapacity, UErrorCode* ec) {
int32_t len = 0;
- if (ec != NULL && U_SUCCESS(*ec)) {
+ if (ec != NULL && U_SUCCESS(*ec)) {
TimeZone* zone = TimeZone::createDefault();
if (zone == NULL) {
*ec = U_MEMORY_ALLOCATION_ERROR;
@@ -91,23 +91,23 @@ ucal_setDefaultTimeZone(const UChar* zoneID, UErrorCode* ec) {
}
}
-U_DRAFT int32_t U_EXPORT2
-ucal_getHostTimeZone(UChar* result, int32_t resultCapacity, UErrorCode* ec) {
- int32_t len = 0;
- if (ec != NULL && U_SUCCESS(*ec)) {
- TimeZone *zone = TimeZone::detectHostTimeZone();
- if (zone == NULL) {
- *ec = U_MEMORY_ALLOCATION_ERROR;
- } else {
- UnicodeString id;
- zone->getID(id);
- delete zone;
- len = id.extract(result, resultCapacity, *ec);
- }
- }
- return len;
-}
-
+U_DRAFT int32_t U_EXPORT2
+ucal_getHostTimeZone(UChar* result, int32_t resultCapacity, UErrorCode* ec) {
+ int32_t len = 0;
+ if (ec != NULL && U_SUCCESS(*ec)) {
+ TimeZone *zone = TimeZone::detectHostTimeZone();
+ if (zone == NULL) {
+ *ec = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ UnicodeString id;
+ zone->getID(id);
+ delete zone;
+ len = id.extract(result, resultCapacity, *ec);
+ }
+ }
+ return len;
+}
+
U_CAPI int32_t U_EXPORT2
ucal_getDSTSavings(const UChar* zoneID, UErrorCode* ec) {
int32_t result = 0;
@@ -154,43 +154,43 @@ ucal_open( const UChar* zoneID,
UCalendarType caltype,
UErrorCode* status)
{
- if (U_FAILURE(*status)) {
- return nullptr;
- }
+ if (U_FAILURE(*status)) {
+ return nullptr;
+ }
- LocalPointer<TimeZone> zone( (zoneID==nullptr) ? TimeZone::createDefault()
- : _createTimeZone(zoneID, len, status), *status);
+ LocalPointer<TimeZone> zone( (zoneID==nullptr) ? TimeZone::createDefault()
+ : _createTimeZone(zoneID, len, status), *status);
if (U_FAILURE(*status)) {
- return nullptr;
+ return nullptr;
}
if ( caltype == UCAL_GREGORIAN ) {
- char localeBuf[ULOC_LOCALE_IDENTIFIER_CAPACITY];
- if ( locale == nullptr ) {
+ char localeBuf[ULOC_LOCALE_IDENTIFIER_CAPACITY];
+ if ( locale == nullptr ) {
locale = uloc_getDefault();
}
- int32_t localeLength = static_cast<int32_t>(uprv_strlen(locale));
- if (localeLength >= ULOC_LOCALE_IDENTIFIER_CAPACITY) {
- *status = U_ILLEGAL_ARGUMENT_ERROR;
- return nullptr;
- }
- uprv_strcpy(localeBuf, locale);
+ int32_t localeLength = static_cast<int32_t>(uprv_strlen(locale));
+ if (localeLength >= ULOC_LOCALE_IDENTIFIER_CAPACITY) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return nullptr;
+ }
+ uprv_strcpy(localeBuf, locale);
uloc_setKeywordValue("calendar", "gregorian", localeBuf, ULOC_LOCALE_IDENTIFIER_CAPACITY, status);
if (U_FAILURE(*status)) {
- return nullptr;
+ return nullptr;
}
- return (UCalendar*)Calendar::createInstance(zone.orphan(), Locale(localeBuf), *status);
+ return (UCalendar*)Calendar::createInstance(zone.orphan(), Locale(localeBuf), *status);
}
- return (UCalendar*)Calendar::createInstance(zone.orphan(), Locale(locale), *status);
+ return (UCalendar*)Calendar::createInstance(zone.orphan(), Locale(locale), *status);
}
U_CAPI void U_EXPORT2
ucal_close(UCalendar *cal)
{
- if (cal != nullptr) {
- delete (Calendar*) cal;
- }
+ if (cal != nullptr) {
+ delete (Calendar*) cal;
+ }
}
U_CAPI UCalendar* U_EXPORT2
diff --git a/contrib/libs/icu/i18n/ucln_in.cpp b/contrib/libs/icu/i18n/ucln_in.cpp
index f29cbe41dd..94be2af9b4 100644
--- a/contrib/libs/icu/i18n/ucln_in.cpp
+++ b/contrib/libs/icu/i18n/ucln_in.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
@@ -8,7 +8,7 @@
* *
******************************************************************************
* file name: ucln_in.cpp
-* encoding: UTF-8
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
diff --git a/contrib/libs/icu/i18n/ucln_in.h b/contrib/libs/icu/i18n/ucln_in.h
index 765cdd559f..b1e09bc81b 100644
--- a/contrib/libs/icu/i18n/ucln_in.h
+++ b/contrib/libs/icu/i18n/ucln_in.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
@@ -6,7 +6,7 @@
* Corporation and others. All Rights Reserved.
******************************************************************************
* file name: ucln_in.h
-* encoding: UTF-8
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
@@ -26,14 +26,14 @@ 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_UNIT_EXTRAS,
- UCLN_I18N_NUMBER_SKELETONS,
- UCLN_I18N_CURRENCY_SPACING,
+ UCLN_I18N_UNIT_EXTRAS,
+ UCLN_I18N_NUMBER_SKELETONS,
+ UCLN_I18N_CURRENCY_SPACING,
UCLN_I18N_SPOOF,
UCLN_I18N_SPOOFDATA,
UCLN_I18N_TRANSLITERATOR,
UCLN_I18N_REGEX,
- UCLN_I18N_JAPANESE_CALENDAR,
+ UCLN_I18N_JAPANESE_CALENDAR,
UCLN_I18N_ISLAMIC_CALENDAR,
UCLN_I18N_CHINESE_CALENDAR,
UCLN_I18N_HEBREW_CALENDAR,
@@ -60,8 +60,8 @@ typedef enum ECleanupI18NType {
UCLN_I18N_GENDERINFO,
UCLN_I18N_CDFINFO,
UCLN_I18N_REGION,
- UCLN_I18N_LIST_FORMATTER,
- UCLN_I18N_NUMSYS,
+ UCLN_I18N_LIST_FORMATTER,
+ UCLN_I18N_NUMSYS,
UCLN_I18N_COUNT /* This must be last */
} ECleanupI18NType;
diff --git a/contrib/libs/icu/i18n/ucol.cpp b/contrib/libs/icu/i18n/ucol.cpp
index f59333ede3..07f505368a 100644
--- a/contrib/libs/icu/i18n/ucol.cpp
+++ b/contrib/libs/icu/i18n/ucol.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -6,7 +6,7 @@
* Corporation and others. All Rights Reserved.
*******************************************************************************
* file name: ucol.cpp
-* encoding: UTF-8
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
@@ -95,7 +95,7 @@ ucol_safeClone(const UCollator *coll, void * /*stackBuffer*/, int32_t * pBufferS
Collator *newColl = Collator::fromUCollator(coll)->clone();
if (newColl == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
+ return nullptr;
} else {
*status = U_SAFECLONE_ALLOCATED_WARNING;
}
diff --git a/contrib/libs/icu/i18n/ucol_imp.h b/contrib/libs/icu/i18n/ucol_imp.h
index a251fc461d..0f2a7d8e58 100644
--- a/contrib/libs/icu/i18n/ucol_imp.h
+++ b/contrib/libs/icu/i18n/ucol_imp.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -10,7 +10,7 @@
*
* Private implementation header for C collation
* file name: ucol_imp.h
-* encoding: UTF-8
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
diff --git a/contrib/libs/icu/i18n/ucol_res.cpp b/contrib/libs/icu/i18n/ucol_res.cpp
index aa4027eb87..f0d759b702 100644
--- a/contrib/libs/icu/i18n/ucol_res.cpp
+++ b/contrib/libs/icu/i18n/ucol_res.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -6,7 +6,7 @@
* Corporation and others. All Rights Reserved.
*******************************************************************************
* file name: ucol_res.cpp
-* encoding: UTF-8
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
@@ -62,7 +62,7 @@ namespace {
static const UChar *rootRules = NULL;
static int32_t rootRulesLength = 0;
static UResourceBundle *rootBundle = NULL;
-static UInitOnce gInitOnceUcolRes = U_INITONCE_INITIALIZER;
+static UInitOnce gInitOnceUcolRes = U_INITONCE_INITIALIZER;
} // namespace
@@ -74,7 +74,7 @@ ucol_res_cleanup() {
rootRulesLength = 0;
ures_close(rootBundle);
rootBundle = NULL;
- gInitOnceUcolRes.reset();
+ gInitOnceUcolRes.reset();
return TRUE;
}
@@ -97,7 +97,7 @@ U_CDECL_END
void
CollationLoader::appendRootRules(UnicodeString &s) {
UErrorCode errorCode = U_ZERO_ERROR;
- umtx_initOnce(gInitOnceUcolRes, CollationLoader::loadRootRules, errorCode);
+ umtx_initOnce(gInitOnceUcolRes, CollationLoader::loadRootRules, errorCode);
if(U_SUCCESS(errorCode)) {
s.append(rootRules, rootRulesLength);
}
@@ -110,7 +110,7 @@ CollationLoader::loadRules(const char *localeID, const char *collationType,
U_ASSERT(collationType != NULL && *collationType != 0);
// Copy the type for lowercasing.
char type[16];
- int32_t typeLength = static_cast<int32_t>(uprv_strlen(collationType));
+ int32_t typeLength = static_cast<int32_t>(uprv_strlen(collationType));
if(typeLength >= UPRV_LENGTHOF(type)) {
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
return;
@@ -318,7 +318,7 @@ CollationLoader::loadFromCollations(UErrorCode &errorCode) {
// Load the collations/type tailoring, with type fallback.
LocalUResourceBundlePointer localData(
ures_getByKeyWithFallback(collations, type, NULL, &errorCode));
- int32_t typeLength = static_cast<int32_t>(uprv_strlen(type));
+ int32_t typeLength = static_cast<int32_t>(uprv_strlen(type));
if(errorCode == U_MISSING_RESOURCE_ERROR) {
errorCode = U_USING_DEFAULT_WARNING;
typeFallback = TRUE;
@@ -348,7 +348,7 @@ CollationLoader::loadFromCollations(UErrorCode &errorCode) {
const char *actualLocale = ures_getLocaleByType(data, ULOC_ACTUAL_LOCALE, &errorCode);
if(U_FAILURE(errorCode)) { return NULL; }
const char *vLocale = validLocale.getBaseName();
- UBool actualAndValidLocalesAreDifferent = Locale(actualLocale) != Locale(vLocale);
+ UBool actualAndValidLocalesAreDifferent = Locale(actualLocale) != Locale(vLocale);
// Set the collation types on the informational locales,
// except when they match the default types (for brevity and backwards compatibility).
@@ -400,17 +400,17 @@ CollationLoader::loadFromData(UErrorCode &errorCode) {
// Try to fetch the optional rules string.
{
UErrorCode internalErrorCode = U_ZERO_ERROR;
- int32_t len;
- const UChar *s = ures_getStringByKey(data, "Sequence", &len,
+ int32_t len;
+ const UChar *s = ures_getStringByKey(data, "Sequence", &len,
&internalErrorCode);
if(U_SUCCESS(internalErrorCode)) {
- t->rules.setTo(TRUE, s, len);
+ t->rules.setTo(TRUE, s, len);
}
}
const char *actualLocale = locale.getBaseName(); // without type
const char *vLocale = validLocale.getBaseName();
- UBool actualAndValidLocalesAreDifferent = Locale(actualLocale) != Locale(vLocale);
+ UBool actualAndValidLocalesAreDifferent = Locale(actualLocale) != Locale(vLocale);
// For the actual locale, suppress the default type *according to the actual locale*.
// For example, zh has default=pinyin and contains all of the Chinese tailorings.
@@ -426,10 +426,10 @@ CollationLoader::loadFromData(UErrorCode &errorCode) {
LocalUResourceBundlePointer def(
ures_getByKeyWithFallback(actualBundle.getAlias(), "collations/default", NULL,
&internalErrorCode));
- int32_t len;
- const UChar *s = ures_getString(def.getAlias(), &len, &internalErrorCode);
- if(U_SUCCESS(internalErrorCode) && len < UPRV_LENGTHOF(defaultType)) {
- u_UCharsToChars(s, defaultType, len + 1);
+ int32_t len;
+ const UChar *s = ures_getString(def.getAlias(), &len, &internalErrorCode);
+ if(U_SUCCESS(internalErrorCode) && len < UPRV_LENGTHOF(defaultType)) {
+ u_UCharsToChars(s, defaultType, len + 1);
} else {
uprv_strcpy(defaultType, "standard");
}
@@ -451,7 +451,7 @@ CollationLoader::loadFromData(UErrorCode &errorCode) {
const CollationCacheEntry *entry = new CollationCacheEntry(validLocale, t.getAlias());
if(entry == NULL) {
errorCode = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
+ return nullptr;
} else {
t.orphan();
}
@@ -681,7 +681,7 @@ ucol_getKeywordValuesForLocale(const char* /*key*/, const char* locale,
return NULL;
}
memcpy(en, &defaultKeywordValues, sizeof(UEnumeration));
- ulist_resetList(sink.values); // Initialize the iterator.
+ ulist_resetList(sink.values); // Initialize the iterator.
en->context = sink.values;
sink.values = NULL; // Avoid deletion in the sink destructor.
return en;
diff --git a/contrib/libs/icu/i18n/ucol_sit.cpp b/contrib/libs/icu/i18n/ucol_sit.cpp
index 92f332d6d0..367d4167ea 100644
--- a/contrib/libs/icu/i18n/ucol_sit.cpp
+++ b/contrib/libs/icu/i18n/ucol_sit.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -6,7 +6,7 @@
* Corporation and others. All Rights Reserved.
*******************************************************************************
* file name: ucol_sit.cpp
-* encoding: UTF-8
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
@@ -24,11 +24,11 @@
#include "cstring.h"
#include "uresimp.h"
#include "unicode/coll.h"
-#include "unicode/stringpiece.h"
-#include "charstr.h"
-
-U_NAMESPACE_USE
+#include "unicode/stringpiece.h"
+#include "charstr.h"
+U_NAMESPACE_USE
+
#ifdef UCOL_TRACE_SIT
# include <stdio.h>
#endif
@@ -93,31 +93,31 @@ static const int32_t internalBufferSize = 512;
* collator instance
*/
struct CollatorSpec {
- inline CollatorSpec();
-
- CharString locElements[locElementCount];
- CharString locale;
+ inline CollatorSpec();
+
+ CharString locElements[locElementCount];
+ CharString locale;
UColAttributeValue options[UCOL_ATTRIBUTE_COUNT];
uint32_t variableTopValue;
UChar variableTopString[locElementCapacity];
int32_t variableTopStringLen;
UBool variableTopSet;
- CharString entries[UCOL_SIT_ITEMS_COUNT];
+ CharString entries[UCOL_SIT_ITEMS_COUNT];
};
-CollatorSpec::CollatorSpec() :
-locale(),
-variableTopValue(0),
-variableTopString(),
-variableTopSet(FALSE)
- {
- // set collation options to default
- for(int32_t i = 0; i < UCOL_ATTRIBUTE_COUNT; i++) {
- options[i] = UCOL_DEFAULT;
- }
-}
-
-
+CollatorSpec::CollatorSpec() :
+locale(),
+variableTopValue(0),
+variableTopString(),
+variableTopSet(FALSE)
+ {
+ // set collation options to default
+ for(int32_t i = 0; i < UCOL_ATTRIBUTE_COUNT; i++) {
+ options[i] = UCOL_DEFAULT;
+ }
+}
+
+
/* structure for converting between character attribute
* representation and real collation attribute value.
*/
@@ -171,11 +171,11 @@ _processLocaleElement(CollatorSpec *spec, uint32_t value, const char* string,
{
do {
if(value == UCOL_SIT_LANGUAGE || value == UCOL_SIT_KEYWORD || value == UCOL_SIT_PROVIDER) {
- spec->locElements[value].append(uprv_tolower(*string), *status);
+ spec->locElements[value].append(uprv_tolower(*string), *status);
} else {
- spec->locElements[value].append(*string, *status);
+ spec->locElements[value].append(*string, *status);
}
- } while(*(++string) != '_' && *string && U_SUCCESS(*status));
+ } while(*(++string) != '_' && *string && U_SUCCESS(*status));
// don't skip the underscore at the end
return string;
}
@@ -193,7 +193,7 @@ _processRFC3066Locale(CollatorSpec *spec, uint32_t, const char* string,
*status = U_BUFFER_OVERFLOW_ERROR;
return string;
} else {
- spec->locale.copyFrom(CharString(string, static_cast<int32_t>(end-string), *status), *status);
+ spec->locale.copyFrom(CharString(string, static_cast<int32_t>(end-string), *status), *status);
return end+1;
}
}
@@ -315,11 +315,11 @@ const char* ucol_sit_readOption(const char *start, CollatorSpec *spec,
for(i = 0; i < UCOL_SIT_ITEMS_COUNT; i++) {
if(*start == options[i].optionStart) {
const char* end = options[i].action(spec, options[i].attr, start+1, status);
-#ifdef UCOL_TRACE_SIT
- fprintf(stderr, "***Set %d to %s...\n", i, start);
-#endif
- // assume 'start' does not go away through all this
- spec->entries[i].copyFrom(CharString(start, (int32_t)(end - start), *status), *status);
+#ifdef UCOL_TRACE_SIT
+ fprintf(stderr, "***Set %d to %s...\n", i, start);
+#endif
+ // assume 'start' does not go away through all this
+ spec->entries[i].copyFrom(CharString(start, (int32_t)(end - start), *status), *status);
return end;
}
}
@@ -356,25 +356,25 @@ int32_t ucol_sit_dumpSpecs(CollatorSpec *s, char *destination, int32_t capacity,
char optName;
if(U_SUCCESS(*status)) {
for(i = 0; i < UCOL_SIT_ITEMS_COUNT; i++) {
- if(!s->entries[i].isEmpty()) {
+ if(!s->entries[i].isEmpty()) {
if(len) {
if(len < capacity) {
uprv_strcat(destination, "_");
}
len++;
}
- optName = s->entries[i][0];
+ optName = s->entries[i][0];
if(optName == languageArg || optName == regionArg || optName == variantArg || optName == keywordArg) {
- for(j = 0; j < s->entries[i].length(); j++) {
+ for(j = 0; j < s->entries[i].length(); j++) {
if(len + j < capacity) {
- destination[len+j] = uprv_toupper(s->entries[i][j]);
+ destination[len+j] = uprv_toupper(s->entries[i][j]);
}
}
- len += s->entries[i].length();
+ len += s->entries[i].length();
} else {
- len += s->entries[i].length();
+ len += s->entries[i].length();
if(len < capacity) {
- uprv_strncat(destination,s->entries[i].data(), s->entries[i].length());
+ uprv_strncat(destination,s->entries[i].data(), s->entries[i].length());
}
}
}
@@ -386,40 +386,40 @@ int32_t ucol_sit_dumpSpecs(CollatorSpec *s, char *destination, int32_t capacity,
}
static void
-ucol_sit_calculateWholeLocale(CollatorSpec *s, UErrorCode &status) {
+ucol_sit_calculateWholeLocale(CollatorSpec *s, UErrorCode &status) {
// put the locale together, unless we have a done
// locale
- if(s->locale.isEmpty()) {
+ if(s->locale.isEmpty()) {
// first the language
- s->locale.append(s->locElements[UCOL_SIT_LANGUAGE], status);
+ s->locale.append(s->locElements[UCOL_SIT_LANGUAGE], status);
// then the script, if present
- if(!s->locElements[UCOL_SIT_SCRIPT].isEmpty()) {
- s->locale.append("_", status);
- s->locale.append(s->locElements[UCOL_SIT_SCRIPT], status);
+ if(!s->locElements[UCOL_SIT_SCRIPT].isEmpty()) {
+ s->locale.append("_", status);
+ s->locale.append(s->locElements[UCOL_SIT_SCRIPT], status);
}
// then the region, if present
- if(!s->locElements[UCOL_SIT_REGION].isEmpty()) {
- s->locale.append("_", status);
- s->locale.append(s->locElements[UCOL_SIT_REGION], status);
- } else if(!s->locElements[UCOL_SIT_VARIANT].isEmpty()) { // if there is a variant, we need an underscore
- s->locale.append("_", status);
+ if(!s->locElements[UCOL_SIT_REGION].isEmpty()) {
+ s->locale.append("_", status);
+ s->locale.append(s->locElements[UCOL_SIT_REGION], status);
+ } else if(!s->locElements[UCOL_SIT_VARIANT].isEmpty()) { // if there is a variant, we need an underscore
+ s->locale.append("_", status);
}
// add variant, if there
- if(!s->locElements[UCOL_SIT_VARIANT].isEmpty()) {
- s->locale.append("_", status);
- s->locale.append(s->locElements[UCOL_SIT_VARIANT], status);
+ if(!s->locElements[UCOL_SIT_VARIANT].isEmpty()) {
+ s->locale.append("_", status);
+ s->locale.append(s->locElements[UCOL_SIT_VARIANT], status);
}
// if there is a collation keyword, add that too
- if(!s->locElements[UCOL_SIT_KEYWORD].isEmpty()) {
- s->locale.append(collationKeyword, status);
- s->locale.append(s->locElements[UCOL_SIT_KEYWORD], status);
+ if(!s->locElements[UCOL_SIT_KEYWORD].isEmpty()) {
+ s->locale.append(collationKeyword, status);
+ s->locale.append(s->locElements[UCOL_SIT_KEYWORD], status);
}
// if there is a provider keyword, add that too
- if(!s->locElements[UCOL_SIT_PROVIDER].isEmpty()) {
- s->locale.append(providerKeyword, status);
- s->locale.append(s->locElements[UCOL_SIT_PROVIDER], status);
+ if(!s->locElements[UCOL_SIT_PROVIDER].isEmpty()) {
+ s->locale.append(providerKeyword, status);
+ s->locale.append(s->locElements[UCOL_SIT_PROVIDER], status);
}
}
}
@@ -451,11 +451,11 @@ ucol_prepareShortStringOpen( const char *definition,
// analyse the string in order to get everything we need.
CollatorSpec s;
ucol_sit_readSpecs(&s, definition, parseError, status);
- ucol_sit_calculateWholeLocale(&s, *status);
+ ucol_sit_calculateWholeLocale(&s, *status);
char buffer[internalBufferSize];
uprv_memset(buffer, 0, internalBufferSize);
- uloc_canonicalize(s.locale.data(), buffer, internalBufferSize, status);
+ uloc_canonicalize(s.locale.data(), buffer, internalBufferSize, status);
UResourceBundle *b = ures_open(U_ICUDATA_COLL, buffer, status);
/* we try to find stuff from keyword */
@@ -463,15 +463,15 @@ ucol_prepareShortStringOpen( const char *definition,
UResourceBundle *collElem = NULL;
char keyBuffer[256];
// if there is a keyword, we pick it up and try to get elements
- int32_t keyLen = uloc_getKeywordValue(buffer, "collation", keyBuffer, sizeof(keyBuffer), status);
- // Treat too long a value as no keyword.
- if(keyLen >= (int32_t)sizeof(keyBuffer)) {
- keyLen = 0;
- *status = U_ZERO_ERROR;
- }
- if(keyLen == 0) {
- // no keyword
- // we try to find the default setting, which will give us the keyword value
+ int32_t keyLen = uloc_getKeywordValue(buffer, "collation", keyBuffer, sizeof(keyBuffer), status);
+ // Treat too long a value as no keyword.
+ if(keyLen >= (int32_t)sizeof(keyBuffer)) {
+ keyLen = 0;
+ *status = U_ZERO_ERROR;
+ }
+ if(keyLen == 0) {
+ // no keyword
+ // we try to find the default setting, which will give us the keyword value
UResourceBundle *defaultColl = ures_getByKeyWithFallback(collations, "default", NULL, status);
if(U_SUCCESS(*status)) {
int32_t defaultKeyLen = 0;
@@ -521,14 +521,14 @@ ucol_openFromShortString( const char *definition,
const char *string = definition;
CollatorSpec s;
string = ucol_sit_readSpecs(&s, definition, parseError, status);
- ucol_sit_calculateWholeLocale(&s, *status);
+ ucol_sit_calculateWholeLocale(&s, *status);
char buffer[internalBufferSize];
uprv_memset(buffer, 0, internalBufferSize);
-#ifdef UCOL_TRACE_SIT
- fprintf(stderr, "DEF %s, DATA %s, ERR %s\n", definition, s.locale.data(), u_errorName(*status));
-#endif
- uloc_canonicalize(s.locale.data(), buffer, internalBufferSize, status);
+#ifdef UCOL_TRACE_SIT
+ fprintf(stderr, "DEF %s, DATA %s, ERR %s\n", definition, s.locale.data(), u_errorName(*status));
+#endif
+ uloc_canonicalize(s.locale.data(), buffer, internalBufferSize, status);
UCollator *result = ucol_open(buffer, status);
int32_t i = 0;
diff --git a/contrib/libs/icu/i18n/ucoleitr.cpp b/contrib/libs/icu/i18n/ucoleitr.cpp
index 596ce03295..c20f08a69e 100644
--- a/contrib/libs/icu/i18n/ucoleitr.cpp
+++ b/contrib/libs/icu/i18n/ucoleitr.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
diff --git a/contrib/libs/icu/i18n/ucsdet.cpp b/contrib/libs/icu/i18n/ucsdet.cpp
index 46f69cf90c..452fc4298c 100644
--- a/contrib/libs/icu/i18n/ucsdet.cpp
+++ b/contrib/libs/icu/i18n/ucsdet.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
********************************************************************************
diff --git a/contrib/libs/icu/i18n/udat.cpp b/contrib/libs/icu/i18n/udat.cpp
index ab91bcff41..8be8d06ba2 100644
--- a/contrib/libs/icu/i18n/udat.cpp
+++ b/contrib/libs/icu/i18n/udat.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -167,14 +167,14 @@ udat_open(UDateFormatStyle timeStyle,
}
}
- if(fmt == nullptr) {
+ if(fmt == nullptr) {
*status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
- if (U_FAILURE(*status)) {
- delete fmt;
- return nullptr;
+ return nullptr;
}
+ if (U_FAILURE(*status)) {
+ delete fmt;
+ return nullptr;
+ }
if(tzID != 0) {
TimeZone *zone = TimeZone::createTimeZone(UnicodeString((UBool)(tzIDLength == -1), tzID, tzIDLength));
@@ -607,7 +607,7 @@ udat_getSymbols(const UDateFormat *fmt,
} else {
return -1;
}
- int32_t count = 0;
+ int32_t count = 0;
const UnicodeString *res = NULL;
switch(type) {
diff --git a/contrib/libs/icu/i18n/udateintervalformat.cpp b/contrib/libs/icu/i18n/udateintervalformat.cpp
index 388960384b..58dcfbd4be 100644
--- a/contrib/libs/icu/i18n/udateintervalformat.cpp
+++ b/contrib/libs/icu/i18n/udateintervalformat.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*****************************************************************************************
@@ -18,21 +18,21 @@
#include "unicode/timezone.h"
#include "unicode/locid.h"
#include "unicode/unistr.h"
-#include "formattedval_impl.h"
+#include "formattedval_impl.h"
U_NAMESPACE_USE
-// Magic number: FDIV in ASCII
-UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL(
- FormattedDateInterval,
- UFormattedDateInterval,
- UFormattedDateIntervalImpl,
- UFormattedDateIntervalApiHelper,
- udtitvfmt,
- 0x46444956)
-
-
+// Magic number: FDIV in ASCII
+UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL(
+ FormattedDateInterval,
+ UFormattedDateInterval,
+ UFormattedDateIntervalImpl,
+ UFormattedDateIntervalApiHelper,
+ udtitvfmt,
+ 0x46444956)
+
+
U_CAPI UDateIntervalFormat* U_EXPORT2
udtitvfmt_open(const char* locale,
const UChar* skeleton,
@@ -116,40 +116,40 @@ udtitvfmt_format(const UDateIntervalFormat* formatter,
}
-U_DRAFT void U_EXPORT2
-udtitvfmt_formatToResult(
- const UDateIntervalFormat* formatter,
- UDate fromDate,
- UDate toDate,
- UFormattedDateInterval* result,
- UErrorCode* status) {
- if (U_FAILURE(*status)) {
- return;
- }
- auto* resultImpl = UFormattedDateIntervalApiHelper::validate(result, *status);
- DateInterval interval = DateInterval(fromDate,toDate);
- if (resultImpl != nullptr) {
- resultImpl->fImpl = reinterpret_cast<const DateIntervalFormat*>(formatter)
- ->formatToValue(interval, *status);
- }
-}
-
-U_DRAFT void U_EXPORT2
-udtitvfmt_formatCalendarToResult(
- const UDateIntervalFormat* formatter,
- UCalendar* fromCalendar,
- UCalendar* toCalendar,
- UFormattedDateInterval* result,
- UErrorCode* status) {
- if (U_FAILURE(*status)) {
- return;
- }
- auto* resultImpl = UFormattedDateIntervalApiHelper::validate(result, *status);
- if (resultImpl != nullptr) {
- resultImpl->fImpl = reinterpret_cast<const DateIntervalFormat*>(formatter)
- ->formatToValue(*(Calendar *)fromCalendar, *(Calendar *)toCalendar, *status);
- }
-}
-
-
+U_DRAFT void U_EXPORT2
+udtitvfmt_formatToResult(
+ const UDateIntervalFormat* formatter,
+ UDate fromDate,
+ UDate toDate,
+ UFormattedDateInterval* result,
+ UErrorCode* status) {
+ if (U_FAILURE(*status)) {
+ return;
+ }
+ auto* resultImpl = UFormattedDateIntervalApiHelper::validate(result, *status);
+ DateInterval interval = DateInterval(fromDate,toDate);
+ if (resultImpl != nullptr) {
+ resultImpl->fImpl = reinterpret_cast<const DateIntervalFormat*>(formatter)
+ ->formatToValue(interval, *status);
+ }
+}
+
+U_DRAFT void U_EXPORT2
+udtitvfmt_formatCalendarToResult(
+ const UDateIntervalFormat* formatter,
+ UCalendar* fromCalendar,
+ UCalendar* toCalendar,
+ UFormattedDateInterval* result,
+ UErrorCode* status) {
+ if (U_FAILURE(*status)) {
+ return;
+ }
+ auto* resultImpl = UFormattedDateIntervalApiHelper::validate(result, *status);
+ if (resultImpl != nullptr) {
+ resultImpl->fImpl = reinterpret_cast<const DateIntervalFormat*>(formatter)
+ ->formatToValue(*(Calendar *)fromCalendar, *(Calendar *)toCalendar, *status);
+ }
+}
+
+
#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/udatpg.cpp b/contrib/libs/icu/i18n/udatpg.cpp
index 332636a938..0e8c36183c 100644
--- a/contrib/libs/icu/i18n/udatpg.cpp
+++ b/contrib/libs/icu/i18n/udatpg.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -8,7 +8,7 @@
*
*******************************************************************************
* file name: udatpg.cpp
-* encoding: UTF-8
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
@@ -181,25 +181,25 @@ udatpg_getAppendItemName(const UDateTimePatternGenerator *dtpg,
return result.getBuffer();
}
-U_CAPI int32_t U_EXPORT2
-udatpg_getFieldDisplayName(const UDateTimePatternGenerator *dtpg,
- UDateTimePatternField field,
- UDateTimePGDisplayWidth width,
- UChar *fieldName, int32_t capacity,
- UErrorCode *pErrorCode) {
- if (U_FAILURE(*pErrorCode))
- return -1;
- if (fieldName == NULL ? capacity != 0 : capacity < 0) {
- *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
- return -1;
- }
- UnicodeString result = ((const DateTimePatternGenerator *)dtpg)->getFieldDisplayName(field,width);
- if (fieldName == NULL) {
- return result.length();
- }
- return result.extract(fieldName, capacity, *pErrorCode);
-}
-
+U_CAPI int32_t U_EXPORT2
+udatpg_getFieldDisplayName(const UDateTimePatternGenerator *dtpg,
+ UDateTimePatternField field,
+ UDateTimePGDisplayWidth width,
+ UChar *fieldName, int32_t capacity,
+ UErrorCode *pErrorCode) {
+ if (U_FAILURE(*pErrorCode))
+ return -1;
+ if (fieldName == NULL ? capacity != 0 : capacity < 0) {
+ *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
+ UnicodeString result = ((const DateTimePatternGenerator *)dtpg)->getFieldDisplayName(field,width);
+ if (fieldName == NULL) {
+ return result.length();
+ }
+ return result.extract(fieldName, capacity, *pErrorCode);
+}
+
U_CAPI void U_EXPORT2
udatpg_setDateTimeFormat(const UDateTimePatternGenerator *dtpg,
const UChar *dtFormat, int32_t length) {
@@ -291,9 +291,9 @@ udatpg_getPatternForSkeleton(const UDateTimePatternGenerator *dtpg,
return result.getBuffer();
}
-U_CAPI UDateFormatHourCycle U_EXPORT2
-udatpg_getDefaultHourCycle(const UDateTimePatternGenerator *dtpg, UErrorCode* pErrorCode) {
- return ((const DateTimePatternGenerator *)dtpg)->getDefaultHourCycle(*pErrorCode);
-}
-
+U_CAPI UDateFormatHourCycle U_EXPORT2
+udatpg_getDefaultHourCycle(const UDateTimePatternGenerator *dtpg, UErrorCode* pErrorCode) {
+ return ((const DateTimePatternGenerator *)dtpg)->getDefaultHourCycle(*pErrorCode);
+}
+
#endif
diff --git a/contrib/libs/icu/i18n/ufieldpositer.cpp b/contrib/libs/icu/i18n/ufieldpositer.cpp
index 64de856c30..4c7d9c14c1 100644
--- a/contrib/libs/icu/i18n/ufieldpositer.cpp
+++ b/contrib/libs/icu/i18n/ufieldpositer.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*****************************************************************************************
diff --git a/contrib/libs/icu/i18n/uitercollationiterator.cpp b/contrib/libs/icu/i18n/uitercollationiterator.cpp
index 103c91cac8..b342c1fe36 100644
--- a/contrib/libs/icu/i18n/uitercollationiterator.cpp
+++ b/contrib/libs/icu/i18n/uitercollationiterator.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/uitercollationiterator.h b/contrib/libs/icu/i18n/uitercollationiterator.h
index 62b6f83419..6ebd706b57 100644
--- a/contrib/libs/icu/i18n/uitercollationiterator.h
+++ b/contrib/libs/icu/i18n/uitercollationiterator.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/ulistformatter.cpp b/contrib/libs/icu/i18n/ulistformatter.cpp
index bfb7cf96bd..38d3d06be4 100644
--- a/contrib/libs/icu/i18n/ulistformatter.cpp
+++ b/contrib/libs/icu/i18n/ulistformatter.cpp
@@ -1,160 +1,160 @@
-// © 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/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/ulistformatter.h"
-#include "unicode/listformatter.h"
-#include "unicode/localpointer.h"
-#include "cmemory.h"
-#include "formattedval_impl.h"
-
-U_NAMESPACE_USE
-
-U_CAPI UListFormatter* U_EXPORT2
-ulistfmt_open(const char* locale,
- UErrorCode* status)
-{
- if (U_FAILURE(*status)) {
- return NULL;
- }
- LocalPointer<ListFormatter> listfmt(ListFormatter::createInstance(Locale(locale), *status));
- if (U_FAILURE(*status)) {
- return NULL;
- }
- return (UListFormatter*)listfmt.orphan();
-}
-
-
-U_CAPI UListFormatter* U_EXPORT2
-ulistfmt_openForType(const char* locale, UListFormatterType type,
- UListFormatterWidth width, UErrorCode* status)
-{
- if (U_FAILURE(*status)) {
- return NULL;
- }
- LocalPointer<ListFormatter> listfmt(ListFormatter::createInstance(Locale(locale), type, width, *status));
- if (U_FAILURE(*status)) {
- return NULL;
- }
- return (UListFormatter*)listfmt.orphan();
-}
-
-
-U_CAPI void U_EXPORT2
-ulistfmt_close(UListFormatter *listfmt)
-{
- delete (ListFormatter*)listfmt;
-}
-
-
-// Magic number: FLST in ASCII
-UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL(
- FormattedList,
- UFormattedList,
- UFormattedListImpl,
- UFormattedListApiHelper,
- ulistfmt,
- 0x464C5354)
-
-
-static UnicodeString* getUnicodeStrings(
- const UChar* const strings[],
- const int32_t* stringLengths,
- int32_t stringCount,
- UnicodeString* length4StackBuffer,
- LocalArray<UnicodeString>& maybeOwner,
- UErrorCode& status) {
- U_ASSERT(U_SUCCESS(status));
- if (stringCount < 0 || (strings == NULL && stringCount > 0)) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return nullptr;
- }
- UnicodeString* ustrings = length4StackBuffer;
- if (stringCount > 4) {
- maybeOwner.adoptInsteadAndCheckErrorCode(new UnicodeString[stringCount], status);
- if (U_FAILURE(status)) {
- return nullptr;
- }
- ustrings = maybeOwner.getAlias();
- }
- if (stringLengths == NULL) {
- for (int32_t stringIndex = 0; stringIndex < stringCount; stringIndex++) {
- ustrings[stringIndex].setTo(TRUE, strings[stringIndex], -1);
- }
- } else {
- for (int32_t stringIndex = 0; stringIndex < stringCount; stringIndex++) {
- ustrings[stringIndex].setTo(stringLengths[stringIndex] < 0, strings[stringIndex], stringLengths[stringIndex]);
- }
- }
- return ustrings;
-}
-
-
-U_CAPI int32_t U_EXPORT2
-ulistfmt_format(const UListFormatter* listfmt,
- const UChar* const strings[],
- const int32_t * stringLengths,
- int32_t stringCount,
- UChar* result,
- int32_t resultCapacity,
- UErrorCode* status)
-{
- if (U_FAILURE(*status)) {
- return -1;
- }
- if ((result == NULL) ? resultCapacity != 0 : resultCapacity < 0) {
- *status = U_ILLEGAL_ARGUMENT_ERROR;
- return -1;
- }
- UnicodeString length4StackBuffer[4];
- LocalArray<UnicodeString> maybeOwner;
- UnicodeString* ustrings = getUnicodeStrings(
- strings, stringLengths, stringCount, length4StackBuffer, maybeOwner, *status);
- if (U_FAILURE(*status)) {
- return -1;
- }
- UnicodeString res;
- if (result != NULL) {
- // NULL destination for pure preflighting: empty dummy string
- // otherwise, alias the destination buffer (copied from udat_format)
- res.setTo(result, 0, resultCapacity);
- }
- reinterpret_cast<const ListFormatter*>(listfmt)->format( ustrings, stringCount, res, *status );
- return res.extract(result, resultCapacity, *status);
-}
-
-
-U_CAPI void U_EXPORT2
-ulistfmt_formatStringsToResult(
- const UListFormatter* listfmt,
- const UChar* const strings[],
- const int32_t * stringLengths,
- int32_t stringCount,
- UFormattedList* uresult,
- UErrorCode* status) {
- auto* result = UFormattedListApiHelper::validate(uresult, *status);
- if (U_FAILURE(*status)) {
- return;
- }
- UnicodeString length4StackBuffer[4];
- LocalArray<UnicodeString> maybeOwner;
- UnicodeString* ustrings = getUnicodeStrings(
- strings, stringLengths, stringCount, length4StackBuffer, maybeOwner, *status);
- if (U_FAILURE(*status)) {
- return;
- }
- result->fImpl = reinterpret_cast<const ListFormatter*>(listfmt)
- ->formatStringsToValue(ustrings, stringCount, *status);
-}
-
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 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/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/ulistformatter.h"
+#include "unicode/listformatter.h"
+#include "unicode/localpointer.h"
+#include "cmemory.h"
+#include "formattedval_impl.h"
+
+U_NAMESPACE_USE
+
+U_CAPI UListFormatter* U_EXPORT2
+ulistfmt_open(const char* locale,
+ UErrorCode* status)
+{
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ LocalPointer<ListFormatter> listfmt(ListFormatter::createInstance(Locale(locale), *status));
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ return (UListFormatter*)listfmt.orphan();
+}
+
+
+U_CAPI UListFormatter* U_EXPORT2
+ulistfmt_openForType(const char* locale, UListFormatterType type,
+ UListFormatterWidth width, UErrorCode* status)
+{
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ LocalPointer<ListFormatter> listfmt(ListFormatter::createInstance(Locale(locale), type, width, *status));
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ return (UListFormatter*)listfmt.orphan();
+}
+
+
+U_CAPI void U_EXPORT2
+ulistfmt_close(UListFormatter *listfmt)
+{
+ delete (ListFormatter*)listfmt;
+}
+
+
+// Magic number: FLST in ASCII
+UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL(
+ FormattedList,
+ UFormattedList,
+ UFormattedListImpl,
+ UFormattedListApiHelper,
+ ulistfmt,
+ 0x464C5354)
+
+
+static UnicodeString* getUnicodeStrings(
+ const UChar* const strings[],
+ const int32_t* stringLengths,
+ int32_t stringCount,
+ UnicodeString* length4StackBuffer,
+ LocalArray<UnicodeString>& maybeOwner,
+ UErrorCode& status) {
+ U_ASSERT(U_SUCCESS(status));
+ if (stringCount < 0 || (strings == NULL && stringCount > 0)) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return nullptr;
+ }
+ UnicodeString* ustrings = length4StackBuffer;
+ if (stringCount > 4) {
+ maybeOwner.adoptInsteadAndCheckErrorCode(new UnicodeString[stringCount], status);
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ ustrings = maybeOwner.getAlias();
+ }
+ if (stringLengths == NULL) {
+ for (int32_t stringIndex = 0; stringIndex < stringCount; stringIndex++) {
+ ustrings[stringIndex].setTo(TRUE, strings[stringIndex], -1);
+ }
+ } else {
+ for (int32_t stringIndex = 0; stringIndex < stringCount; stringIndex++) {
+ ustrings[stringIndex].setTo(stringLengths[stringIndex] < 0, strings[stringIndex], stringLengths[stringIndex]);
+ }
+ }
+ return ustrings;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+ulistfmt_format(const UListFormatter* listfmt,
+ const UChar* const strings[],
+ const int32_t * stringLengths,
+ int32_t stringCount,
+ UChar* result,
+ int32_t resultCapacity,
+ UErrorCode* status)
+{
+ if (U_FAILURE(*status)) {
+ return -1;
+ }
+ if ((result == NULL) ? resultCapacity != 0 : resultCapacity < 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
+ UnicodeString length4StackBuffer[4];
+ LocalArray<UnicodeString> maybeOwner;
+ UnicodeString* ustrings = getUnicodeStrings(
+ strings, stringLengths, stringCount, length4StackBuffer, maybeOwner, *status);
+ if (U_FAILURE(*status)) {
+ return -1;
+ }
+ UnicodeString res;
+ if (result != NULL) {
+ // NULL destination for pure preflighting: empty dummy string
+ // otherwise, alias the destination buffer (copied from udat_format)
+ res.setTo(result, 0, resultCapacity);
+ }
+ reinterpret_cast<const ListFormatter*>(listfmt)->format( ustrings, stringCount, res, *status );
+ return res.extract(result, resultCapacity, *status);
+}
+
+
+U_CAPI void U_EXPORT2
+ulistfmt_formatStringsToResult(
+ const UListFormatter* listfmt,
+ const UChar* const strings[],
+ const int32_t * stringLengths,
+ int32_t stringCount,
+ UFormattedList* uresult,
+ UErrorCode* status) {
+ auto* result = UFormattedListApiHelper::validate(uresult, *status);
+ if (U_FAILURE(*status)) {
+ return;
+ }
+ UnicodeString length4StackBuffer[4];
+ LocalArray<UnicodeString> maybeOwner;
+ UnicodeString* ustrings = getUnicodeStrings(
+ strings, stringLengths, stringCount, length4StackBuffer, maybeOwner, *status);
+ if (U_FAILURE(*status)) {
+ return;
+ }
+ result->fImpl = reinterpret_cast<const ListFormatter*>(listfmt)
+ ->formatStringsToValue(ustrings, stringCount, *status);
+}
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/ulocdata.cpp b/contrib/libs/icu/i18n/ulocdata.cpp
index 7f4e7b9b11..fbe6137bdd 100644
--- a/contrib/libs/icu/i18n/ulocdata.cpp
+++ b/contrib/libs/icu/i18n/ulocdata.cpp
@@ -1,386 +1,386 @@
-// © 2016 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html
-/*
-******************************************************************************
-* *
-* Copyright (C) 2003-2016, International Business Machines *
-* Corporation and others. All Rights Reserved. *
-* *
-******************************************************************************
-* file name: ulocdata.c
-* encoding: UTF-8
-* tab size: 8 (not used)
-* indentation:4
-*
-* created on: 2003Oct21
-* created by: Ram Viswanadha,John Emmons
-*/
-
-#include "cmemory.h"
-#include "unicode/ustring.h"
-#include "unicode/ures.h"
-#include "unicode/uloc.h"
-#include "unicode/ulocdata.h"
-#include "uresimp.h"
-#include "ureslocs.h"
-#include "ulocimp.h"
-
-#define MEASUREMENT_SYSTEM "MeasurementSystem"
-#define PAPER_SIZE "PaperSize"
-
-/** A locale data object.
- * For usage in C programs.
- * @draft ICU 3.4
- */
-struct ULocaleData {
- /**
- * Controls the "No Substitute" behavior of this locale data object
- */
- UBool noSubstitute;
-
- /**
- * Pointer to the resource bundle associated with this locale data object
- */
- UResourceBundle *bundle;
-
- /**
- * Pointer to the lang resource bundle associated with this locale data object
- */
- UResourceBundle *langBundle;
-};
-
-U_CAPI ULocaleData* U_EXPORT2
-ulocdata_open(const char *localeID, UErrorCode *status)
-{
- ULocaleData *uld;
-
- if (U_FAILURE(*status)) {
- return NULL;
- }
-
- uld = (ULocaleData *)uprv_malloc(sizeof(ULocaleData));
- if (uld == NULL) {
- *status = U_MEMORY_ALLOCATION_ERROR;
- return(NULL);
- }
-
- uld->langBundle = NULL;
-
- uld->noSubstitute = FALSE;
- uld->bundle = ures_open(NULL, localeID, status);
- uld->langBundle = ures_open(U_ICUDATA_LANG, localeID, status);
-
- if (U_FAILURE(*status)) {
- uprv_free(uld);
- return NULL;
- }
-
- return uld;
-}
-
-U_CAPI void U_EXPORT2
-ulocdata_close(ULocaleData *uld)
-{
- if ( uld != NULL ) {
- ures_close(uld->langBundle);
- ures_close(uld->bundle);
- uprv_free(uld);
- }
-}
-
-U_CAPI void U_EXPORT2
-ulocdata_setNoSubstitute(ULocaleData *uld, UBool setting)
-{
- uld->noSubstitute = setting;
-}
-
-U_CAPI UBool U_EXPORT2
-ulocdata_getNoSubstitute(ULocaleData *uld)
-{
- return uld->noSubstitute;
-}
-
-U_CAPI USet* U_EXPORT2
-ulocdata_getExemplarSet(ULocaleData *uld, USet *fillIn,
- uint32_t options, ULocaleDataExemplarSetType extype, UErrorCode *status){
-
- static const char* const exemplarSetTypes[] = { "ExemplarCharacters",
- "AuxExemplarCharacters",
- "ExemplarCharactersIndex",
- "ExemplarCharactersPunctuation"};
- const UChar *exemplarChars = NULL;
- int32_t len = 0;
- UErrorCode localStatus = U_ZERO_ERROR;
-
- if (U_FAILURE(*status))
- return NULL;
-
- exemplarChars = ures_getStringByKey(uld->bundle, exemplarSetTypes[extype], &len, &localStatus);
- if ( (localStatus == U_USING_DEFAULT_WARNING) && uld->noSubstitute ) {
- localStatus = U_MISSING_RESOURCE_ERROR;
- }
-
- if (localStatus != U_ZERO_ERROR) {
- *status = localStatus;
- }
-
- if (U_FAILURE(*status))
- return NULL;
-
- if(fillIn != NULL)
- uset_applyPattern(fillIn, exemplarChars, len,
- USET_IGNORE_SPACE | options, status);
- else
- fillIn = uset_openPatternOptions(exemplarChars, len,
- USET_IGNORE_SPACE | options, status);
-
- return fillIn;
-
-}
-
-U_CAPI int32_t U_EXPORT2
-ulocdata_getDelimiter(ULocaleData *uld, ULocaleDataDelimiterType type,
- UChar *result, int32_t resultLength, UErrorCode *status){
-
- static const char* const delimiterKeys[] = {
- "quotationStart",
- "quotationEnd",
- "alternateQuotationStart",
- "alternateQuotationEnd"
- };
-
- UResourceBundle *delimiterBundle;
- int32_t len = 0;
- const UChar *delimiter = NULL;
- UErrorCode localStatus = U_ZERO_ERROR;
-
- if (U_FAILURE(*status))
- return 0;
-
- delimiterBundle = ures_getByKey(uld->bundle, "delimiters", NULL, &localStatus);
-
- if ( (localStatus == U_USING_DEFAULT_WARNING) && uld->noSubstitute ) {
- localStatus = U_MISSING_RESOURCE_ERROR;
- }
-
- if (localStatus != U_ZERO_ERROR) {
- *status = localStatus;
- }
-
- if (U_FAILURE(*status)){
- ures_close(delimiterBundle);
- return 0;
- }
-
- delimiter = ures_getStringByKey(delimiterBundle, delimiterKeys[type], &len, &localStatus);
- ures_close(delimiterBundle);
-
- if ( (localStatus == U_USING_DEFAULT_WARNING) && uld->noSubstitute ) {
- localStatus = U_MISSING_RESOURCE_ERROR;
- }
-
- if (localStatus != U_ZERO_ERROR) {
- *status = localStatus;
- }
-
- if (U_FAILURE(*status)){
- return 0;
- }
-
- u_strncpy(result,delimiter, resultLength);
- return len;
-}
-
-static UResourceBundle * measurementTypeBundleForLocale(const char *localeID, const char *measurementType, UErrorCode *status){
- char region[ULOC_COUNTRY_CAPACITY];
- UResourceBundle *rb;
- UResourceBundle *measTypeBundle = NULL;
-
- ulocimp_getRegionForSupplementalData(localeID, TRUE, region, ULOC_COUNTRY_CAPACITY, status);
-
- rb = ures_openDirect(NULL, "supplementalData", status);
- ures_getByKey(rb, "measurementData", rb, status);
- if (rb != NULL) {
- UResourceBundle *measDataBundle = ures_getByKey(rb, region, NULL, status);
- if (U_SUCCESS(*status)) {
- measTypeBundle = ures_getByKey(measDataBundle, measurementType, NULL, status);
- }
- if (*status == U_MISSING_RESOURCE_ERROR) {
- *status = U_ZERO_ERROR;
- if (measDataBundle != NULL) {
- ures_close(measDataBundle);
- }
- measDataBundle = ures_getByKey(rb, "001", NULL, status);
- measTypeBundle = ures_getByKey(measDataBundle, measurementType, NULL, status);
- }
- ures_close(measDataBundle);
- }
- ures_close(rb);
- return measTypeBundle;
-}
-
-U_CAPI UMeasurementSystem U_EXPORT2
-ulocdata_getMeasurementSystem(const char *localeID, UErrorCode *status){
-
- UResourceBundle* measurement=NULL;
- UMeasurementSystem system = UMS_LIMIT;
-
- if(status == NULL || U_FAILURE(*status)){
- return system;
- }
-
- measurement = measurementTypeBundleForLocale(localeID, MEASUREMENT_SYSTEM, status);
- system = (UMeasurementSystem) ures_getInt(measurement, status);
-
- ures_close(measurement);
-
- return system;
-
-}
-
-U_CAPI void U_EXPORT2
-ulocdata_getPaperSize(const char* localeID, int32_t *height, int32_t *width, UErrorCode *status){
- UResourceBundle* paperSizeBundle = NULL;
- const int32_t* paperSize=NULL;
- int32_t len = 0;
-
- if(status == NULL || U_FAILURE(*status)){
- return;
- }
-
- paperSizeBundle = measurementTypeBundleForLocale(localeID, PAPER_SIZE, status);
- paperSize = ures_getIntVector(paperSizeBundle, &len, status);
-
- if(U_SUCCESS(*status)){
- if(len < 2){
- *status = U_INTERNAL_PROGRAM_ERROR;
- }else{
- *height = paperSize[0];
- *width = paperSize[1];
- }
- }
-
- ures_close(paperSizeBundle);
-
-}
-
-U_CAPI void U_EXPORT2
-ulocdata_getCLDRVersion(UVersionInfo versionArray, UErrorCode *status) {
- UResourceBundle *rb = NULL;
- rb = ures_openDirect(NULL, "supplementalData", status);
- ures_getVersionByKey(rb, "cldrVersion", versionArray, status);
- ures_close(rb);
-}
-
-U_CAPI int32_t U_EXPORT2
-ulocdata_getLocaleDisplayPattern(ULocaleData *uld,
- UChar *result,
- int32_t resultCapacity,
- UErrorCode *status) {
- UResourceBundle *patternBundle;
- int32_t len = 0;
- const UChar *pattern = NULL;
- UErrorCode localStatus = U_ZERO_ERROR;
-
- if (U_FAILURE(*status))
- return 0;
-
- patternBundle = ures_getByKey(uld->langBundle, "localeDisplayPattern", NULL, &localStatus);
-
- if ( (localStatus == U_USING_DEFAULT_WARNING) && uld->noSubstitute ) {
- localStatus = U_MISSING_RESOURCE_ERROR;
- }
-
- if (localStatus != U_ZERO_ERROR) {
- *status = localStatus;
- }
-
- if (U_FAILURE(*status)){
- ures_close(patternBundle);
- return 0;
- }
-
- pattern = ures_getStringByKey(patternBundle, "pattern", &len, &localStatus);
- ures_close(patternBundle);
-
- if ( (localStatus == U_USING_DEFAULT_WARNING) && uld->noSubstitute ) {
- localStatus = U_MISSING_RESOURCE_ERROR;
- }
-
- if (localStatus != U_ZERO_ERROR) {
- *status = localStatus;
- }
-
- if (U_FAILURE(*status)){
- return 0;
- }
-
- u_strncpy(result, pattern, resultCapacity);
- return len;
-}
-
-
-U_CAPI int32_t U_EXPORT2
-ulocdata_getLocaleSeparator(ULocaleData *uld,
- UChar *result,
- int32_t resultCapacity,
- UErrorCode *status) {
- UResourceBundle *separatorBundle;
- int32_t len = 0;
- const UChar *separator = NULL;
- UErrorCode localStatus = U_ZERO_ERROR;
- UChar *p0, *p1;
- static const UChar sub0[4] = { 0x007b, 0x0030, 0x007d , 0x0000 }; /* {0} */
- static const UChar sub1[4] = { 0x007b, 0x0031, 0x007d , 0x0000 }; /* {1} */
- static const int32_t subLen = 3;
-
- if (U_FAILURE(*status))
- return 0;
-
- separatorBundle = ures_getByKey(uld->langBundle, "localeDisplayPattern", NULL, &localStatus);
-
- if ( (localStatus == U_USING_DEFAULT_WARNING) && uld->noSubstitute ) {
- localStatus = U_MISSING_RESOURCE_ERROR;
- }
-
- if (localStatus != U_ZERO_ERROR) {
- *status = localStatus;
- }
-
- if (U_FAILURE(*status)){
- ures_close(separatorBundle);
- return 0;
- }
-
- separator = ures_getStringByKey(separatorBundle, "separator", &len, &localStatus);
- ures_close(separatorBundle);
-
- if ( (localStatus == U_USING_DEFAULT_WARNING) && uld->noSubstitute ) {
- localStatus = U_MISSING_RESOURCE_ERROR;
- }
-
- if (localStatus != U_ZERO_ERROR) {
- *status = localStatus;
- }
-
- if (U_FAILURE(*status)){
- return 0;
- }
-
- /* For backwards compatibility, if we have a pattern, return the portion between {0} and {1} */
- p0=u_strstr(separator, sub0);
- p1=u_strstr(separator, sub1);
- if (p0!=NULL && p1!=NULL && p0<=p1) {
- separator = (const UChar *)p0 + subLen;
- len = static_cast<int32_t>(p1 - separator);
- /* Desired separator is no longer zero-terminated; handle that if necessary */
- if (len < resultCapacity) {
- u_strncpy(result, separator, len);
- result[len] = 0;
- return len;
- }
- }
-
- u_strncpy(result, separator, resultCapacity);
- return len;
-}
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+******************************************************************************
+* *
+* Copyright (C) 2003-2016, International Business Machines *
+* Corporation and others. All Rights Reserved. *
+* *
+******************************************************************************
+* file name: ulocdata.c
+* encoding: UTF-8
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2003Oct21
+* created by: Ram Viswanadha,John Emmons
+*/
+
+#include "cmemory.h"
+#include "unicode/ustring.h"
+#include "unicode/ures.h"
+#include "unicode/uloc.h"
+#include "unicode/ulocdata.h"
+#include "uresimp.h"
+#include "ureslocs.h"
+#include "ulocimp.h"
+
+#define MEASUREMENT_SYSTEM "MeasurementSystem"
+#define PAPER_SIZE "PaperSize"
+
+/** A locale data object.
+ * For usage in C programs.
+ * @draft ICU 3.4
+ */
+struct ULocaleData {
+ /**
+ * Controls the "No Substitute" behavior of this locale data object
+ */
+ UBool noSubstitute;
+
+ /**
+ * Pointer to the resource bundle associated with this locale data object
+ */
+ UResourceBundle *bundle;
+
+ /**
+ * Pointer to the lang resource bundle associated with this locale data object
+ */
+ UResourceBundle *langBundle;
+};
+
+U_CAPI ULocaleData* U_EXPORT2
+ulocdata_open(const char *localeID, UErrorCode *status)
+{
+ ULocaleData *uld;
+
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+
+ uld = (ULocaleData *)uprv_malloc(sizeof(ULocaleData));
+ if (uld == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return(NULL);
+ }
+
+ uld->langBundle = NULL;
+
+ uld->noSubstitute = FALSE;
+ uld->bundle = ures_open(NULL, localeID, status);
+ uld->langBundle = ures_open(U_ICUDATA_LANG, localeID, status);
+
+ if (U_FAILURE(*status)) {
+ uprv_free(uld);
+ return NULL;
+ }
+
+ return uld;
+}
+
+U_CAPI void U_EXPORT2
+ulocdata_close(ULocaleData *uld)
+{
+ if ( uld != NULL ) {
+ ures_close(uld->langBundle);
+ ures_close(uld->bundle);
+ uprv_free(uld);
+ }
+}
+
+U_CAPI void U_EXPORT2
+ulocdata_setNoSubstitute(ULocaleData *uld, UBool setting)
+{
+ uld->noSubstitute = setting;
+}
+
+U_CAPI UBool U_EXPORT2
+ulocdata_getNoSubstitute(ULocaleData *uld)
+{
+ return uld->noSubstitute;
+}
+
+U_CAPI USet* U_EXPORT2
+ulocdata_getExemplarSet(ULocaleData *uld, USet *fillIn,
+ uint32_t options, ULocaleDataExemplarSetType extype, UErrorCode *status){
+
+ static const char* const exemplarSetTypes[] = { "ExemplarCharacters",
+ "AuxExemplarCharacters",
+ "ExemplarCharactersIndex",
+ "ExemplarCharactersPunctuation"};
+ const UChar *exemplarChars = NULL;
+ int32_t len = 0;
+ UErrorCode localStatus = U_ZERO_ERROR;
+
+ if (U_FAILURE(*status))
+ return NULL;
+
+ exemplarChars = ures_getStringByKey(uld->bundle, exemplarSetTypes[extype], &len, &localStatus);
+ if ( (localStatus == U_USING_DEFAULT_WARNING) && uld->noSubstitute ) {
+ localStatus = U_MISSING_RESOURCE_ERROR;
+ }
+
+ if (localStatus != U_ZERO_ERROR) {
+ *status = localStatus;
+ }
+
+ if (U_FAILURE(*status))
+ return NULL;
+
+ if(fillIn != NULL)
+ uset_applyPattern(fillIn, exemplarChars, len,
+ USET_IGNORE_SPACE | options, status);
+ else
+ fillIn = uset_openPatternOptions(exemplarChars, len,
+ USET_IGNORE_SPACE | options, status);
+
+ return fillIn;
+
+}
+
+U_CAPI int32_t U_EXPORT2
+ulocdata_getDelimiter(ULocaleData *uld, ULocaleDataDelimiterType type,
+ UChar *result, int32_t resultLength, UErrorCode *status){
+
+ static const char* const delimiterKeys[] = {
+ "quotationStart",
+ "quotationEnd",
+ "alternateQuotationStart",
+ "alternateQuotationEnd"
+ };
+
+ UResourceBundle *delimiterBundle;
+ int32_t len = 0;
+ const UChar *delimiter = NULL;
+ UErrorCode localStatus = U_ZERO_ERROR;
+
+ if (U_FAILURE(*status))
+ return 0;
+
+ delimiterBundle = ures_getByKey(uld->bundle, "delimiters", NULL, &localStatus);
+
+ if ( (localStatus == U_USING_DEFAULT_WARNING) && uld->noSubstitute ) {
+ localStatus = U_MISSING_RESOURCE_ERROR;
+ }
+
+ if (localStatus != U_ZERO_ERROR) {
+ *status = localStatus;
+ }
+
+ if (U_FAILURE(*status)){
+ ures_close(delimiterBundle);
+ return 0;
+ }
+
+ delimiter = ures_getStringByKey(delimiterBundle, delimiterKeys[type], &len, &localStatus);
+ ures_close(delimiterBundle);
+
+ if ( (localStatus == U_USING_DEFAULT_WARNING) && uld->noSubstitute ) {
+ localStatus = U_MISSING_RESOURCE_ERROR;
+ }
+
+ if (localStatus != U_ZERO_ERROR) {
+ *status = localStatus;
+ }
+
+ if (U_FAILURE(*status)){
+ return 0;
+ }
+
+ u_strncpy(result,delimiter, resultLength);
+ return len;
+}
+
+static UResourceBundle * measurementTypeBundleForLocale(const char *localeID, const char *measurementType, UErrorCode *status){
+ char region[ULOC_COUNTRY_CAPACITY];
+ UResourceBundle *rb;
+ UResourceBundle *measTypeBundle = NULL;
+
+ ulocimp_getRegionForSupplementalData(localeID, TRUE, region, ULOC_COUNTRY_CAPACITY, status);
+
+ rb = ures_openDirect(NULL, "supplementalData", status);
+ ures_getByKey(rb, "measurementData", rb, status);
+ if (rb != NULL) {
+ UResourceBundle *measDataBundle = ures_getByKey(rb, region, NULL, status);
+ if (U_SUCCESS(*status)) {
+ measTypeBundle = ures_getByKey(measDataBundle, measurementType, NULL, status);
+ }
+ if (*status == U_MISSING_RESOURCE_ERROR) {
+ *status = U_ZERO_ERROR;
+ if (measDataBundle != NULL) {
+ ures_close(measDataBundle);
+ }
+ measDataBundle = ures_getByKey(rb, "001", NULL, status);
+ measTypeBundle = ures_getByKey(measDataBundle, measurementType, NULL, status);
+ }
+ ures_close(measDataBundle);
+ }
+ ures_close(rb);
+ return measTypeBundle;
+}
+
+U_CAPI UMeasurementSystem U_EXPORT2
+ulocdata_getMeasurementSystem(const char *localeID, UErrorCode *status){
+
+ UResourceBundle* measurement=NULL;
+ UMeasurementSystem system = UMS_LIMIT;
+
+ if(status == NULL || U_FAILURE(*status)){
+ return system;
+ }
+
+ measurement = measurementTypeBundleForLocale(localeID, MEASUREMENT_SYSTEM, status);
+ system = (UMeasurementSystem) ures_getInt(measurement, status);
+
+ ures_close(measurement);
+
+ return system;
+
+}
+
+U_CAPI void U_EXPORT2
+ulocdata_getPaperSize(const char* localeID, int32_t *height, int32_t *width, UErrorCode *status){
+ UResourceBundle* paperSizeBundle = NULL;
+ const int32_t* paperSize=NULL;
+ int32_t len = 0;
+
+ if(status == NULL || U_FAILURE(*status)){
+ return;
+ }
+
+ paperSizeBundle = measurementTypeBundleForLocale(localeID, PAPER_SIZE, status);
+ paperSize = ures_getIntVector(paperSizeBundle, &len, status);
+
+ if(U_SUCCESS(*status)){
+ if(len < 2){
+ *status = U_INTERNAL_PROGRAM_ERROR;
+ }else{
+ *height = paperSize[0];
+ *width = paperSize[1];
+ }
+ }
+
+ ures_close(paperSizeBundle);
+
+}
+
+U_CAPI void U_EXPORT2
+ulocdata_getCLDRVersion(UVersionInfo versionArray, UErrorCode *status) {
+ UResourceBundle *rb = NULL;
+ rb = ures_openDirect(NULL, "supplementalData", status);
+ ures_getVersionByKey(rb, "cldrVersion", versionArray, status);
+ ures_close(rb);
+}
+
+U_CAPI int32_t U_EXPORT2
+ulocdata_getLocaleDisplayPattern(ULocaleData *uld,
+ UChar *result,
+ int32_t resultCapacity,
+ UErrorCode *status) {
+ UResourceBundle *patternBundle;
+ int32_t len = 0;
+ const UChar *pattern = NULL;
+ UErrorCode localStatus = U_ZERO_ERROR;
+
+ if (U_FAILURE(*status))
+ return 0;
+
+ patternBundle = ures_getByKey(uld->langBundle, "localeDisplayPattern", NULL, &localStatus);
+
+ if ( (localStatus == U_USING_DEFAULT_WARNING) && uld->noSubstitute ) {
+ localStatus = U_MISSING_RESOURCE_ERROR;
+ }
+
+ if (localStatus != U_ZERO_ERROR) {
+ *status = localStatus;
+ }
+
+ if (U_FAILURE(*status)){
+ ures_close(patternBundle);
+ return 0;
+ }
+
+ pattern = ures_getStringByKey(patternBundle, "pattern", &len, &localStatus);
+ ures_close(patternBundle);
+
+ if ( (localStatus == U_USING_DEFAULT_WARNING) && uld->noSubstitute ) {
+ localStatus = U_MISSING_RESOURCE_ERROR;
+ }
+
+ if (localStatus != U_ZERO_ERROR) {
+ *status = localStatus;
+ }
+
+ if (U_FAILURE(*status)){
+ return 0;
+ }
+
+ u_strncpy(result, pattern, resultCapacity);
+ return len;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+ulocdata_getLocaleSeparator(ULocaleData *uld,
+ UChar *result,
+ int32_t resultCapacity,
+ UErrorCode *status) {
+ UResourceBundle *separatorBundle;
+ int32_t len = 0;
+ const UChar *separator = NULL;
+ UErrorCode localStatus = U_ZERO_ERROR;
+ UChar *p0, *p1;
+ static const UChar sub0[4] = { 0x007b, 0x0030, 0x007d , 0x0000 }; /* {0} */
+ static const UChar sub1[4] = { 0x007b, 0x0031, 0x007d , 0x0000 }; /* {1} */
+ static const int32_t subLen = 3;
+
+ if (U_FAILURE(*status))
+ return 0;
+
+ separatorBundle = ures_getByKey(uld->langBundle, "localeDisplayPattern", NULL, &localStatus);
+
+ if ( (localStatus == U_USING_DEFAULT_WARNING) && uld->noSubstitute ) {
+ localStatus = U_MISSING_RESOURCE_ERROR;
+ }
+
+ if (localStatus != U_ZERO_ERROR) {
+ *status = localStatus;
+ }
+
+ if (U_FAILURE(*status)){
+ ures_close(separatorBundle);
+ return 0;
+ }
+
+ separator = ures_getStringByKey(separatorBundle, "separator", &len, &localStatus);
+ ures_close(separatorBundle);
+
+ if ( (localStatus == U_USING_DEFAULT_WARNING) && uld->noSubstitute ) {
+ localStatus = U_MISSING_RESOURCE_ERROR;
+ }
+
+ if (localStatus != U_ZERO_ERROR) {
+ *status = localStatus;
+ }
+
+ if (U_FAILURE(*status)){
+ return 0;
+ }
+
+ /* For backwards compatibility, if we have a pattern, return the portion between {0} and {1} */
+ p0=u_strstr(separator, sub0);
+ p1=u_strstr(separator, sub1);
+ if (p0!=NULL && p1!=NULL && p0<=p1) {
+ separator = (const UChar *)p0 + subLen;
+ len = static_cast<int32_t>(p1 - separator);
+ /* Desired separator is no longer zero-terminated; handle that if necessary */
+ if (len < resultCapacity) {
+ u_strncpy(result, separator, len);
+ result[len] = 0;
+ return len;
+ }
+ }
+
+ u_strncpy(result, separator, resultCapacity);
+ return len;
+}
diff --git a/contrib/libs/icu/i18n/umsg.cpp b/contrib/libs/icu/i18n/umsg.cpp
index 9a5344e019..f4019fe479 100644
--- a/contrib/libs/icu/i18n/umsg.cpp
+++ b/contrib/libs/icu/i18n/umsg.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -8,7 +8,7 @@
*
*******************************************************************************
* file name: umsg.cpp
-* encoding: UTF-8
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
@@ -321,7 +321,7 @@ umsg_applyPattern(UMessageFormat *fmt,
if(status ==NULL||U_FAILURE(*status)){
return ;
}
- if(fmt==NULL || (pattern==NULL && patternLength!=0) || patternLength<-1) {
+ if(fmt==NULL || (pattern==NULL && patternLength!=0) || patternLength<-1) {
*status=U_ILLEGAL_ARGUMENT_ERROR;
return ;
}
@@ -330,7 +330,7 @@ umsg_applyPattern(UMessageFormat *fmt,
parseError = &tErr;
}
- // UnicodeString(pattern, -1) calls u_strlen().
+ // UnicodeString(pattern, -1) calls u_strlen().
((MessageFormat*)fmt)->applyPattern(UnicodeString(pattern,patternLength),*parseError,*status);
}
@@ -463,7 +463,7 @@ umsg_vformat( const UMessageFormat *fmt,
default:
// Unknown/unsupported argument type.
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
}
UnicodeString resultStr;
@@ -590,11 +590,11 @@ umsg_vparse(const UMessageFormat *fmt,
// support kObject. When MessageFormat is changed to
// understand MeasureFormats, modify this code to do the
// right thing. [alan]
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
// better not happen!
case Formattable::kArray:
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
}
diff --git a/contrib/libs/icu/i18n/umsg_imp.h b/contrib/libs/icu/i18n/umsg_imp.h
index 43ef1c78f0..2e080dc337 100644
--- a/contrib/libs/icu/i18n/umsg_imp.h
+++ b/contrib/libs/icu/i18n/umsg_imp.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -6,7 +6,7 @@
* Corporation and others. All Rights Reserved.
**********************************************************************
* file name: umsg_imp.h
-* encoding: UTF-8
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
diff --git a/contrib/libs/icu/i18n/unesctrn.cpp b/contrib/libs/icu/i18n/unesctrn.cpp
index 0636fe1d14..68549a64f9 100644
--- a/contrib/libs/icu/i18n/unesctrn.cpp
+++ b/contrib/libs/icu/i18n/unesctrn.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -164,7 +164,7 @@ UnescapeTransliterator::~UnescapeTransliterator() {
/**
* Transliterator API.
*/
-UnescapeTransliterator* UnescapeTransliterator::clone() const {
+UnescapeTransliterator* UnescapeTransliterator::clone() const {
return new UnescapeTransliterator(*this);
}
diff --git a/contrib/libs/icu/i18n/unesctrn.h b/contrib/libs/icu/i18n/unesctrn.h
index 57dd8d32cf..7bd2c29d89 100644
--- a/contrib/libs/icu/i18n/unesctrn.h
+++ b/contrib/libs/icu/i18n/unesctrn.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -77,7 +77,7 @@ class UnescapeTransliterator : public Transliterator {
/**
* Transliterator API.
*/
- virtual UnescapeTransliterator* clone() const;
+ virtual UnescapeTransliterator* clone() const;
/**
* ICU "poor man's RTTI", returns a UClassID for the actual class.
diff --git a/contrib/libs/icu/i18n/uni2name.cpp b/contrib/libs/icu/i18n/uni2name.cpp
index 41d5c931e4..81048b91ba 100644
--- a/contrib/libs/icu/i18n/uni2name.cpp
+++ b/contrib/libs/icu/i18n/uni2name.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -60,7 +60,7 @@ UnicodeNameTransliterator::UnicodeNameTransliterator(const UnicodeNameTransliter
/**
* Transliterator API.
*/
-UnicodeNameTransliterator* UnicodeNameTransliterator::clone() const {
+UnicodeNameTransliterator* UnicodeNameTransliterator::clone() const {
return new UnicodeNameTransliterator(*this);
}
diff --git a/contrib/libs/icu/i18n/uni2name.h b/contrib/libs/icu/i18n/uni2name.h
index 99309c8e0f..91f24100a6 100644
--- a/contrib/libs/icu/i18n/uni2name.h
+++ b/contrib/libs/icu/i18n/uni2name.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -48,7 +48,7 @@ class UnicodeNameTransliterator : public Transliterator {
/**
* Transliterator API.
*/
- virtual UnicodeNameTransliterator* clone() const;
+ virtual UnicodeNameTransliterator* clone() const;
/**
* ICU "poor man's RTTI", returns a UClassID for the actual class.
diff --git a/contrib/libs/icu/i18n/unum.cpp b/contrib/libs/icu/i18n/unum.cpp
index cce3db7d0b..a0b66dd025 100644
--- a/contrib/libs/icu/i18n/unum.cpp
+++ b/contrib/libs/icu/i18n/unum.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -135,11 +135,11 @@ unum_open( UNumberFormatStyle style,
*status = U_MEMORY_ALLOCATION_ERROR;
}
- if (U_FAILURE(*status) && retVal != NULL) {
- delete retVal;
- retVal = NULL;
- }
-
+ if (U_FAILURE(*status) && retVal != NULL) {
+ delete retVal;
+ retVal = NULL;
+ }
+
return reinterpret_cast<UNumberFormat *>(retVal);
}
@@ -252,34 +252,34 @@ unum_formatDouble( const UNumberFormat* fmt,
return res.extract(result, resultLength, *status);
}
-U_CAPI int32_t U_EXPORT2
-unum_formatDoubleForFields(const UNumberFormat* format,
- double number,
- UChar* result,
- int32_t resultLength,
- UFieldPositionIterator* fpositer,
- UErrorCode* status)
-{
- if (U_FAILURE(*status))
- return -1;
-
- if (result == NULL ? resultLength != 0 : resultLength < 0) {
- *status = U_ILLEGAL_ARGUMENT_ERROR;
- return -1;
- }
-
- UnicodeString res;
- if (result != NULL) {
- // NULL destination for pure preflighting: empty dummy string
- // otherwise, alias the destination buffer
- res.setTo(result, 0, resultLength);
- }
-
- ((const NumberFormat*)format)->format(number, res, (FieldPositionIterator*)fpositer, *status);
-
- return res.extract(result, resultLength, *status);
-}
-
+U_CAPI int32_t U_EXPORT2
+unum_formatDoubleForFields(const UNumberFormat* format,
+ double number,
+ UChar* result,
+ int32_t resultLength,
+ UFieldPositionIterator* fpositer,
+ UErrorCode* status)
+{
+ if (U_FAILURE(*status))
+ return -1;
+
+ if (result == NULL ? resultLength != 0 : resultLength < 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
+
+ UnicodeString res;
+ if (result != NULL) {
+ // NULL destination for pure preflighting: empty dummy string
+ // otherwise, alias the destination buffer
+ res.setTo(result, 0, resultLength);
+ }
+
+ ((const NumberFormat*)format)->format(number, res, (FieldPositionIterator*)fpositer, *status);
+
+ return res.extract(result, resultLength, *status);
+}
+
U_CAPI int32_t U_EXPORT2
unum_formatDecimal(const UNumberFormat* fmt,
const char * number,
@@ -303,7 +303,7 @@ unum_formatDecimal(const UNumberFormat* fmt,
}
if (length < 0) {
- length = static_cast<int32_t>(uprv_strlen(number));
+ length = static_cast<int32_t>(uprv_strlen(number));
}
StringPiece numSP(number, length);
Formattable numFmtbl(numSP, *status);
@@ -512,43 +512,43 @@ U_CAPI int32_t U_EXPORT2
unum_getAttribute(const UNumberFormat* fmt,
UNumberFormatAttribute attr)
{
- const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
- if (attr == UNUM_LENIENT_PARSE) {
- // Supported for all subclasses
- return nf->isLenient();
- }
- else if (attr == UNUM_MAX_INTEGER_DIGITS) {
- return nf->getMaximumIntegerDigits();
- }
- else if (attr == UNUM_MIN_INTEGER_DIGITS) {
- return nf->getMinimumIntegerDigits();
- }
- else if (attr == UNUM_INTEGER_DIGITS) {
- // TODO: what should this return?
- return nf->getMinimumIntegerDigits();
- }
- else if (attr == UNUM_MAX_FRACTION_DIGITS) {
- return nf->getMaximumFractionDigits();
- }
- else if (attr == UNUM_MIN_FRACTION_DIGITS) {
- return nf->getMinimumFractionDigits();
- }
- else if (attr == UNUM_FRACTION_DIGITS) {
- // TODO: what should this return?
- return nf->getMinimumFractionDigits();
- }
- else if (attr == UNUM_ROUNDING_MODE) {
- return nf->getRoundingMode();
- }
-
- // The remaining attributes are only supported for DecimalFormat
- const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
- if (df != NULL) {
- UErrorCode ignoredStatus = U_ZERO_ERROR;
- return df->getAttribute(attr, ignoredStatus);
- }
-
- return -1;
+ const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
+ if (attr == UNUM_LENIENT_PARSE) {
+ // Supported for all subclasses
+ return nf->isLenient();
+ }
+ else if (attr == UNUM_MAX_INTEGER_DIGITS) {
+ return nf->getMaximumIntegerDigits();
+ }
+ else if (attr == UNUM_MIN_INTEGER_DIGITS) {
+ return nf->getMinimumIntegerDigits();
+ }
+ else if (attr == UNUM_INTEGER_DIGITS) {
+ // TODO: what should this return?
+ return nf->getMinimumIntegerDigits();
+ }
+ else if (attr == UNUM_MAX_FRACTION_DIGITS) {
+ return nf->getMaximumFractionDigits();
+ }
+ else if (attr == UNUM_MIN_FRACTION_DIGITS) {
+ return nf->getMinimumFractionDigits();
+ }
+ else if (attr == UNUM_FRACTION_DIGITS) {
+ // TODO: what should this return?
+ return nf->getMinimumFractionDigits();
+ }
+ else if (attr == UNUM_ROUNDING_MODE) {
+ return nf->getRoundingMode();
+ }
+
+ // The remaining attributes are only supported for DecimalFormat
+ const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
+ if (df != NULL) {
+ UErrorCode ignoredStatus = U_ZERO_ERROR;
+ return df->getAttribute(attr, ignoredStatus);
+ }
+
+ return -1;
}
U_CAPI void U_EXPORT2
@@ -556,42 +556,42 @@ unum_setAttribute( UNumberFormat* fmt,
UNumberFormatAttribute attr,
int32_t newValue)
{
- NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
- if (attr == UNUM_LENIENT_PARSE) {
- // Supported for all subclasses
- // keep this here as the class may not be a DecimalFormat
- return nf->setLenient(newValue != 0);
- }
- else if (attr == UNUM_MAX_INTEGER_DIGITS) {
- return nf->setMaximumIntegerDigits(newValue);
- }
- else if (attr == UNUM_MIN_INTEGER_DIGITS) {
- return nf->setMinimumIntegerDigits(newValue);
- }
- else if (attr == UNUM_INTEGER_DIGITS) {
- nf->setMinimumIntegerDigits(newValue);
- return nf->setMaximumIntegerDigits(newValue);
- }
- else if (attr == UNUM_MAX_FRACTION_DIGITS) {
- return nf->setMaximumFractionDigits(newValue);
- }
- else if (attr == UNUM_MIN_FRACTION_DIGITS) {
- return nf->setMinimumFractionDigits(newValue);
- }
- else if (attr == UNUM_FRACTION_DIGITS) {
- nf->setMinimumFractionDigits(newValue);
- return nf->setMaximumFractionDigits(newValue);
- }
- else if (attr == UNUM_ROUNDING_MODE) {
- return nf->setRoundingMode((NumberFormat::ERoundingMode)newValue);
- }
-
- // The remaining attributes are only supported for DecimalFormat
- DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
- if (df != NULL) {
- UErrorCode ignoredStatus = U_ZERO_ERROR;
- df->setAttribute(attr, newValue, ignoredStatus);
- }
+ NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
+ if (attr == UNUM_LENIENT_PARSE) {
+ // Supported for all subclasses
+ // keep this here as the class may not be a DecimalFormat
+ return nf->setLenient(newValue != 0);
+ }
+ else if (attr == UNUM_MAX_INTEGER_DIGITS) {
+ return nf->setMaximumIntegerDigits(newValue);
+ }
+ else if (attr == UNUM_MIN_INTEGER_DIGITS) {
+ return nf->setMinimumIntegerDigits(newValue);
+ }
+ else if (attr == UNUM_INTEGER_DIGITS) {
+ nf->setMinimumIntegerDigits(newValue);
+ return nf->setMaximumIntegerDigits(newValue);
+ }
+ else if (attr == UNUM_MAX_FRACTION_DIGITS) {
+ return nf->setMaximumFractionDigits(newValue);
+ }
+ else if (attr == UNUM_MIN_FRACTION_DIGITS) {
+ return nf->setMinimumFractionDigits(newValue);
+ }
+ else if (attr == UNUM_FRACTION_DIGITS) {
+ nf->setMinimumFractionDigits(newValue);
+ return nf->setMaximumFractionDigits(newValue);
+ }
+ else if (attr == UNUM_ROUNDING_MODE) {
+ return nf->setRoundingMode((NumberFormat::ERoundingMode)newValue);
+ }
+
+ // The remaining attributes are only supported for DecimalFormat
+ DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
+ if (df != NULL) {
+ UErrorCode ignoredStatus = U_ZERO_ERROR;
+ df->setAttribute(attr, newValue, ignoredStatus);
+ }
}
U_CAPI double U_EXPORT2
diff --git a/contrib/libs/icu/i18n/unumsys.cpp b/contrib/libs/icu/i18n/unumsys.cpp
index 4a0d0fa3b6..8ae3d752dd 100644
--- a/contrib/libs/icu/i18n/unumsys.cpp
+++ b/contrib/libs/icu/i18n/unumsys.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*****************************************************************************************
diff --git a/contrib/libs/icu/i18n/upluralrules.cpp b/contrib/libs/icu/i18n/upluralrules.cpp
index 5119257fd8..1563ab09d6 100644
--- a/contrib/libs/icu/i18n/upluralrules.cpp
+++ b/contrib/libs/icu/i18n/upluralrules.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*****************************************************************************************
@@ -15,49 +15,49 @@
#include "unicode/plurrule.h"
#include "unicode/locid.h"
#include "unicode/unistr.h"
-#include "unicode/unum.h"
-#include "unicode/numfmt.h"
-#include "unicode/unumberformatter.h"
-#include "number_decimalquantity.h"
-#include "number_utypes.h"
+#include "unicode/unum.h"
+#include "unicode/numfmt.h"
+#include "unicode/unumberformatter.h"
+#include "number_decimalquantity.h"
+#include "number_utypes.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<const DecimalFormat *>(&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
+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<const DecimalFormat *>(&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)
{
@@ -93,70 +93,70 @@ uplrules_select(const UPluralRules *uplrules,
return result.extract(keyword, capacity, *status);
}
-U_CAPI int32_t U_EXPORT2
-uplrules_selectFormatted(const UPluralRules *uplrules,
- const UFormattedNumber* number,
- UChar *keyword, int32_t capacity,
- UErrorCode *status)
-{
- if (U_FAILURE(*status)) {
- return 0;
- }
- if (keyword == NULL ? capacity != 0 : capacity < 0) {
- *status = U_ILLEGAL_ARGUMENT_ERROR;
- return 0;
- }
- const number::impl::DecimalQuantity* dq =
- number::impl::validateUFormattedNumberToDecimalQuantity(number, *status);
- if (U_FAILURE(*status)) {
- return 0;
- }
- UnicodeString result = ((PluralRules*)uplrules)->select(*dq);
- return result.extract(keyword, capacity, *status);
-}
-
-U_CAPI int32_t U_EXPORT2
-uplrules_selectWithFormat(const UPluralRules *uplrules,
- double number,
- const UNumberFormat *fmt,
- UChar *keyword, int32_t capacity,
- UErrorCode *status)
-{
- if (U_FAILURE(*status)) {
- return 0;
- }
- const PluralRules* plrules = reinterpret_cast<const PluralRules*>(uplrules);
- const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
- if (plrules == NULL || nf == NULL || ((keyword == NULL)? capacity != 0 : capacity < 0)) {
- *status = U_ILLEGAL_ARGUMENT_ERROR;
- return 0;
- }
- Formattable obj(number);
- UnicodeString result = select(*plrules, obj, *nf, *status);
- return result.extract(keyword, capacity, *status);
-}
-
-U_CAPI UEnumeration* U_EXPORT2
-uplrules_getKeywords(const UPluralRules *uplrules,
- UErrorCode *status)
-{
- if (U_FAILURE(*status)) {
- return NULL;
- }
- const PluralRules* plrules = reinterpret_cast<const PluralRules*>(uplrules);
- if (plrules == NULL) {
- *status = U_ILLEGAL_ARGUMENT_ERROR;
- return NULL;
- }
- StringEnumeration *senum = plrules->getKeywords(*status);
- if (U_FAILURE(*status)) {
- return NULL;
- }
- if (senum == NULL) {
- *status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
- return uenum_openFromStringEnumeration(senum, status);
-}
+U_CAPI int32_t U_EXPORT2
+uplrules_selectFormatted(const UPluralRules *uplrules,
+ const UFormattedNumber* number,
+ UChar *keyword, int32_t capacity,
+ UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ if (keyword == NULL ? capacity != 0 : capacity < 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ const number::impl::DecimalQuantity* dq =
+ number::impl::validateUFormattedNumberToDecimalQuantity(number, *status);
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ UnicodeString result = ((PluralRules*)uplrules)->select(*dq);
+ return result.extract(keyword, capacity, *status);
+}
+U_CAPI int32_t U_EXPORT2
+uplrules_selectWithFormat(const UPluralRules *uplrules,
+ double number,
+ const UNumberFormat *fmt,
+ UChar *keyword, int32_t capacity,
+ UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ const PluralRules* plrules = reinterpret_cast<const PluralRules*>(uplrules);
+ const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
+ if (plrules == NULL || nf == NULL || ((keyword == NULL)? capacity != 0 : capacity < 0)) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ Formattable obj(number);
+ UnicodeString result = select(*plrules, obj, *nf, *status);
+ return result.extract(keyword, capacity, *status);
+}
+
+U_CAPI UEnumeration* U_EXPORT2
+uplrules_getKeywords(const UPluralRules *uplrules,
+ UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ const PluralRules* plrules = reinterpret_cast<const PluralRules*>(uplrules);
+ if (plrules == NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+ StringEnumeration *senum = plrules->getKeywords(*status);
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ if (senum == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ return uenum_openFromStringEnumeration(senum, status);
+}
+
#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/uregex.cpp b/contrib/libs/icu/i18n/uregex.cpp
index 7f41918cff..31c5b9f5bc 100644
--- a/contrib/libs/icu/i18n/uregex.cpp
+++ b/contrib/libs/icu/i18n/uregex.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -767,7 +767,7 @@ uregex_start64(URegularExpression *regexp2,
if (validateRE(regexp, TRUE, status) == FALSE) {
return 0;
}
- int64_t result = regexp->fMatcher->start64(groupNum, *status);
+ int64_t result = regexp->fMatcher->start64(groupNum, *status);
return result;
}
@@ -791,7 +791,7 @@ uregex_end64(URegularExpression *regexp2,
if (validateRE(regexp, TRUE, status) == FALSE) {
return 0;
}
- int64_t result = regexp->fMatcher->end64(groupNum, *status);
+ int64_t result = regexp->fMatcher->end64(groupNum, *status);
return result;
}
@@ -1465,10 +1465,10 @@ int32_t RegexCImpl::appendReplacement(RegularExpression *regexp,
int32_t groupNum = 0;
U_ASSERT(c == DOLLARSIGN);
- UChar32 c32 = -1;
- if (replIdx < replacementLength) {
- U16_GET(replacementText, 0, replIdx, replacementLength, c32);
- }
+ UChar32 c32 = -1;
+ if (replIdx < replacementLength) {
+ U16_GET(replacementText, 0, replIdx, replacementLength, c32);
+ }
if (u_isdigit(c32)) {
int32_t numDigits = 0;
int32_t numCaptureGroups = m->fPattern->fGroupMap->size();
@@ -1508,8 +1508,8 @@ int32_t RegexCImpl::appendReplacement(RegularExpression *regexp,
(c32 >= 0x31 && c32 <= 0x39)) { // 0..9
groupName.append(c32);
} else if (c32 == RIGHTBRACKET) {
- groupNum = regexp->fPat->fNamedCaptureMap ?
- uhash_geti(regexp->fPat->fNamedCaptureMap, &groupName) : 0;
+ groupNum = regexp->fPat->fNamedCaptureMap ?
+ uhash_geti(regexp->fPat->fNamedCaptureMap, &groupName) : 0;
if (groupNum == 0) {
// Name not defined by pattern.
*status = U_REGEX_INVALID_CAPTURE_GROUP_NAME;
@@ -1655,8 +1655,8 @@ int32_t RegexCImpl::appendTail(RegularExpression *regexp,
} else if (UTEXT_USES_U16(m->fInputText)) {
srcIdx = (int32_t)nativeIdx;
} else {
- UErrorCode newStatus = U_ZERO_ERROR;
- srcIdx = utext_extract(m->fInputText, 0, nativeIdx, NULL, 0, &newStatus);
+ UErrorCode newStatus = U_ZERO_ERROR;
+ srcIdx = utext_extract(m->fInputText, 0, nativeIdx, NULL, 0, &newStatus);
}
for (;;) {
diff --git a/contrib/libs/icu/i18n/uregexc.cpp b/contrib/libs/icu/i18n/uregexc.cpp
index c7d3bcd2c7..a3b1f24a67 100644
--- a/contrib/libs/icu/i18n/uregexc.cpp
+++ b/contrib/libs/icu/i18n/uregexc.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/uregion.cpp b/contrib/libs/icu/i18n/uregion.cpp
index 79a623730c..a5e141d217 100644
--- a/contrib/libs/icu/i18n/uregion.cpp
+++ b/contrib/libs/icu/i18n/uregion.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*****************************************************************************************
diff --git a/contrib/libs/icu/i18n/usearch.cpp b/contrib/libs/icu/i18n/usearch.cpp
index 8866de7033..532471c7f9 100644
--- a/contrib/libs/icu/i18n/usearch.cpp
+++ b/contrib/libs/icu/i18n/usearch.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -317,7 +317,7 @@ inline uint16_t initializePatternCETable(UStringSearch *strsrch,
uprv_free(pattern->ces);
}
- uint32_t offset = 0;
+ uint32_t offset = 0;
uint16_t result = 0;
int32_t ce;
@@ -388,7 +388,7 @@ inline uint16_t initializePatternPCETable(UStringSearch *strsrch,
uprv_free(pattern->pces);
}
- uint32_t offset = 0;
+ uint32_t offset = 0;
uint16_t result = 0;
int64_t pce;
@@ -498,7 +498,7 @@ inline void setShiftTable(int16_t shift[], int16_t backshift[],
for (count = 0; count < cesize; count ++) {
// number of ces from right of array to the count
int temp = defaultforward - count - 1;
- shift[hashFromCE32(cetable[count])] = temp > 1 ? static_cast<int16_t>(temp) : 1;
+ shift[hashFromCE32(cetable[count])] = temp > 1 ? static_cast<int16_t>(temp) : 1;
}
shift[hashFromCE32(cetable[cesize])] = 1;
// for ignorables we just shift by one. see test examples.
@@ -1351,7 +1351,7 @@ inline int getUnblockedAccentIndex(UChar *accents, int32_t *accentsindex)
* @param destinationlength target array size, returning the appended length
* @param source1 null-terminated first array
* @param source2 second array
-* @param source2length length of second array
+* @param source2length length of second array
* @param source3 null-terminated third array
* @param status error status if any
* @return new destination array, destination if there was no new allocation
@@ -1560,7 +1560,7 @@ inline void cleanUpSafeText(const UStringSearch *strsrch, UChar *safetext,
/**
* Take the rearranged end accents and tries matching. If match failed at
-* a separate preceding set of accents (separated from the rearranged on by
+* a separate preceding set of accents (separated from the rearranged on by
* at least a base character) then we rearrange the preceding accents and
* tries matching again.
* We allow skipping of the ends of the accent set if the ces do not match.
@@ -2220,7 +2220,7 @@ int32_t doPreviousCanonicalSuffixMatch(UStringSearch *strsrch,
/**
* Take the rearranged start accents and tries matching. If match failed at
-* a separate following set of accents (separated from the rearranged on by
+* a separate following set of accents (separated from the rearranged on by
* at least a base character) then we rearrange the preceding accents and
* tries matching again.
* We allow skipping of the ends of the accent set if the ces do not match.
@@ -3545,10 +3545,10 @@ const CEI *CEIBuffer::get(int32_t index) {
// that is allowed.
if (index != limitIx) {
U_ASSERT(FALSE);
- // TODO: In ICU 64 the above assert was changed to use UPRV_UNREACHABLE instead
- // which unconditionally calls abort(). However, there were cases where this was
- // being hit. This change is reverted for now, restoring the existing behavior.
- // ICU-20792 tracks the follow-up work/further investigation on this.
+ // TODO: In ICU 64 the above assert was changed to use UPRV_UNREACHABLE instead
+ // which unconditionally calls abort(). However, there were cases where this was
+ // being hit. This change is reverted for now, restoring the existing behavior.
+ // ICU-20792 tracks the follow-up work/further investigation on this.
return NULL;
}
@@ -3587,10 +3587,10 @@ const CEI *CEIBuffer::getPrevious(int32_t index) {
// that is allowed.
if (index != limitIx) {
U_ASSERT(FALSE);
- // TODO: In ICU 64 the above assert was changed to use UPRV_UNREACHABLE instead
- // which unconditionally calls abort(). However, there were cases where this was
- // being hit. This change is reverted for now, restoring the existing behavior.
- // ICU-20792 tracks the follow-up work/further investigation on this.
+ // TODO: In ICU 64 the above assert was changed to use UPRV_UNREACHABLE instead
+ // which unconditionally calls abort(). However, there were cases where this was
+ // being hit. This change is reverted for now, restoring the existing behavior.
+ // ICU-20792 tracks the follow-up work/further investigation on this.
return NULL;
}
@@ -3862,7 +3862,7 @@ U_CAPI UBool U_EXPORT2 usearch_search(UStringSearch *strsrch,
#endif
// Input parameter sanity check.
- // TODO: should input indices clip to the text length
+ // TODO: should input indices clip to the text length
// in the same way that UText does.
if(strsrch->pattern.cesLength == 0 ||
startIdx < 0 ||
@@ -4024,7 +4024,7 @@ U_CAPI UBool U_EXPORT2 usearch_search(UStringSearch *strsrch,
// Check for the start of the match being within an Collation Element Expansion,
// meaning that the first char of the match is only partially matched.
- // With expansions, the first CE will report the index of the source
+ // With expansions, the first CE will report the index of the source
// character, and all subsequent (expansions) CEs will report the source index of the
// _following_ character.
int32_t secondIx = firstCEI->highIndex;
diff --git a/contrib/libs/icu/i18n/uspoof.cpp b/contrib/libs/icu/i18n/uspoof.cpp
index 33682389f5..bb878c6a44 100644
--- a/contrib/libs/icu/i18n/uspoof.cpp
+++ b/contrib/libs/icu/i18n/uspoof.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
***************************************************************************
@@ -6,7 +6,7 @@
* and others. All Rights Reserved.
***************************************************************************
* file name: uspoof.cpp
-* encoding: UTF-8
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
@@ -43,9 +43,9 @@ static UnicodeSet *gRecommendedSet = NULL;
static const Normalizer2 *gNfdNormalizer = NULL;
static UInitOnce gSpoofInitStaticsOnce = U_INITONCE_INITIALIZER;
-namespace {
-
-UBool U_CALLCONV
+namespace {
+
+UBool U_CALLCONV
uspoof_cleanup(void) {
delete gInclusionSet;
gInclusionSet = NULL;
@@ -56,103 +56,103 @@ uspoof_cleanup(void) {
return TRUE;
}
-void U_CALLCONV initializeStatics(UErrorCode &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;
- }
+void U_CALLCONV initializeStatics(UErrorCode &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 IdentifierStatus.txt & IdentifierType.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.
- 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"\\u04FF\\u0510-\\u0529\\u052E\\u052F\\u0531-\\u0556\\u0559\\u0561-\\u0586"
- u"\\u05B4\\u05D0-\\u05EA\\u05EF-\\u05F2\\u0620-\\u063F\\u0641-\\u0655\\u0660-"
- u"\\u0669\\u0670-\\u0672\\u0674\\u0679-\\u068D\\u068F-\\u06A0\\u06A2-\\u06D3"
- u"\\u06D5\\u06E5\\u06E6\\u06EE-\\u06FC\\u06FF\\u0750-\\u07B1\\u08A0-\\u08AC"
- u"\\u08B2\\u08B6-\\u08C7\\u0901-\\u094D\\u094F\\u0950\\u0956\\u0957\\u0960-"
- u"\\u0963\\u0966-\\u096F\\u0971-\\u0977\\u0979-\\u097F\\u0981-\\u0983\\u0985-"
- u"\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9"
- u"\\u09BC-\\u09C4\\u09C7\\u09C8\\u09CB-\\u09CE\\u09D7\\u09E0-\\u09E3\\u09E6-"
- u"\\u09F1\\u09FE\\u0A01-\\u0A03\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28"
- u"\\u0A2A-\\u0A30\\u0A32\\u0A35\\u0A38\\u0A39\\u0A3C\\u0A3E-\\u0A42\\u0A47"
- u"\\u0A48\\u0A4B-\\u0A4D\\u0A5C\\u0A66-\\u0A74\\u0A81-\\u0A83\\u0A85-\\u0A8D"
- u"\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9"
- u"\\u0ABC-\\u0AC5\\u0AC7-\\u0AC9\\u0ACB-\\u0ACD\\u0AD0\\u0AE0-\\u0AE3\\u0AE6-"
- u"\\u0AEF\\u0AFA-\\u0AFF\\u0B01-\\u0B03\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-"
- u"\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3C-\\u0B43\\u0B47"
- u"\\u0B48\\u0B4B-\\u0B4D\\u0B55-\\u0B57\\u0B5F-\\u0B61\\u0B66-\\u0B6F\\u0B71"
- u"\\u0B82\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A"
- u"\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BBE-"
- u"\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCD\\u0BD0\\u0BD7\\u0BE6-\\u0BEF\\u0C01-"
- u"\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D-"
- u"\\u0C44\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C60\\u0C61\\u0C66-"
- u"\\u0C6F\\u0C80\\u0C82\\u0C83\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8"
- u"\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBC-\\u0CC4\\u0CC6-\\u0CC8\\u0CCA-\\u0CCD"
- u"\\u0CD5\\u0CD6\\u0CE0-\\u0CE3\\u0CE6-\\u0CEF\\u0CF1\\u0CF2\\u0D00\\u0D02"
- u"\\u0D03\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D-\\u0D43\\u0D46-"
- u"\\u0D48\\u0D4A-\\u0D4E\\u0D54-\\u0D57\\u0D60\\u0D61\\u0D66-\\u0D6F\\u0D7A-"
- u"\\u0D7F\\u0D82\\u0D83\\u0D85-\\u0D8E\\u0D91-\\u0D96\\u0D9A-\\u0DA5\\u0DA7-"
- u"\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0DCA\\u0DCF-\\u0DD4\\u0DD6"
- u"\\u0DD8-\\u0DDE\\u0DF2\\u0E01-\\u0E32\\u0E34-\\u0E3A\\u0E40-\\u0E4E\\u0E50-"
- u"\\u0E59\\u0E81\\u0E82\\u0E84\\u0E86-\\u0E8A\\u0E8C-\\u0EA3\\u0EA5\\u0EA7-"
- u"\\u0EB2\\u0EB4-\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EC8-\\u0ECD\\u0ED0-\\u0ED9"
- u"\\u0EDE\\u0EDF\\u0F00\\u0F20-\\u0F29\\u0F35\\u0F37\\u0F3E-\\u0F42\\u0F44-"
- u"\\u0F47\\u0F49-\\u0F4C\\u0F4E-\\u0F51\\u0F53-\\u0F56\\u0F58-\\u0F5B\\u0F5D-"
- u"\\u0F68\\u0F6A-\\u0F6C\\u0F71\\u0F72\\u0F74\\u0F7A-\\u0F80\\u0F82-\\u0F84"
- u"\\u0F86-\\u0F92\\u0F94-\\u0F97\\u0F99-\\u0F9C\\u0F9E-\\u0FA1\\u0FA3-\\u0FA6"
- u"\\u0FA8-\\u0FAB\\u0FAD-\\u0FB8\\u0FBA-\\u0FBC\\u0FC6\\u1000-\\u1049\\u1050-"
- u"\\u109D\\u10C7\\u10CD\\u10D0-\\u10F0\\u10F7-\\u10FA\\u10FD-\\u10FF\\u1200-"
- u"\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288"
- u"\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-"
- u"\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u135D-"
- u"\\u135F\\u1380-\\u138F\\u1780-\\u17A2\\u17A5-\\u17A7\\u17A9-\\u17B3\\u17B6-"
- u"\\u17CA\\u17D2\\u17D7\\u17DC\\u17E0-\\u17E9\\u1C90-\\u1CBA\\u1CBD-\\u1CBF"
- u"\\u1E00-\\u1E99\\u1E9E\\u1EA0-\\u1EF9\\u1F00-\\u1F15\\u1F18-\\u1F1D\\u1F20-"
- u"\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F70"
- u"\\u1F72\\u1F74\\u1F76\\u1F78\\u1F7A\\u1F7C\\u1F80-\\u1FB4\\u1FB6-\\u1FBA"
- u"\\u1FBC\\u1FC2-\\u1FC4\\u1FC6-\\u1FC8\\u1FCA\\u1FCC\\u1FD0-\\u1FD2\\u1FD6-"
- u"\\u1FDA\\u1FE0-\\u1FE2\\u1FE4-\\u1FEA\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FF8"
- u"\\u1FFA\\u1FFC\\u2D27\\u2D2D\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE"
- u"\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6"
- u"\\u2DD8-\\u2DDE\\u3005-\\u3007\\u3041-\\u3096\\u3099\\u309A\\u309D\\u309E"
- u"\\u30A1-\\u30FA\\u30FC-\\u30FE\\u3105-\\u312D\\u312F\\u31A0-\\u31BF\\u3400-"
- u"\\u4DBF\\u4E00-\\u9FFC\\uA67F\\uA717-\\uA71F\\uA788\\uA78D\\uA792\\uA793"
- u"\\uA7AA\\uA7AE\\uA7B8\\uA7B9\\uA7C2-\\uA7CA\\uA9E7-\\uA9FE\\uAA60-\\uAA76"
- u"\\uAA7A-\\uAA7F\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26"
- u"\\uAB28-\\uAB2E\\uAB66\\uAB67\\uAC00-\\uD7A3\\uFA0E\\uFA0F\\uFA11\\uFA13"
- u"\\uFA14\\uFA1F\\uFA21\\uFA23\\uFA24\\uFA27-\\uFA29\\U00011301\\U00011303"
- u"\\U0001133B\\U0001133C\\U00016FF0\\U00016FF1\\U0001B150-\\U0001B152"
- u"\\U0001B164-\\U0001B167\\U00020000-\\U0002A6DD\\U0002A700-\\U0002B734"
- u"\\U0002B740-\\U0002B81D\\U0002B820-\\U0002CEA1\\U0002CEB0-\\U0002EBE0"
- u"\\U00030000-\\U0003134A]";
-
- gRecommendedSet = new UnicodeSet(UnicodeString(recommendedPat), status);
- if (gRecommendedSet == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- delete gInclusionSet;
- return;
- }
+ 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"\\u04FF\\u0510-\\u0529\\u052E\\u052F\\u0531-\\u0556\\u0559\\u0561-\\u0586"
+ u"\\u05B4\\u05D0-\\u05EA\\u05EF-\\u05F2\\u0620-\\u063F\\u0641-\\u0655\\u0660-"
+ u"\\u0669\\u0670-\\u0672\\u0674\\u0679-\\u068D\\u068F-\\u06A0\\u06A2-\\u06D3"
+ u"\\u06D5\\u06E5\\u06E6\\u06EE-\\u06FC\\u06FF\\u0750-\\u07B1\\u08A0-\\u08AC"
+ u"\\u08B2\\u08B6-\\u08C7\\u0901-\\u094D\\u094F\\u0950\\u0956\\u0957\\u0960-"
+ u"\\u0963\\u0966-\\u096F\\u0971-\\u0977\\u0979-\\u097F\\u0981-\\u0983\\u0985-"
+ u"\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9"
+ u"\\u09BC-\\u09C4\\u09C7\\u09C8\\u09CB-\\u09CE\\u09D7\\u09E0-\\u09E3\\u09E6-"
+ u"\\u09F1\\u09FE\\u0A01-\\u0A03\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28"
+ u"\\u0A2A-\\u0A30\\u0A32\\u0A35\\u0A38\\u0A39\\u0A3C\\u0A3E-\\u0A42\\u0A47"
+ u"\\u0A48\\u0A4B-\\u0A4D\\u0A5C\\u0A66-\\u0A74\\u0A81-\\u0A83\\u0A85-\\u0A8D"
+ u"\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9"
+ u"\\u0ABC-\\u0AC5\\u0AC7-\\u0AC9\\u0ACB-\\u0ACD\\u0AD0\\u0AE0-\\u0AE3\\u0AE6-"
+ u"\\u0AEF\\u0AFA-\\u0AFF\\u0B01-\\u0B03\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-"
+ u"\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3C-\\u0B43\\u0B47"
+ u"\\u0B48\\u0B4B-\\u0B4D\\u0B55-\\u0B57\\u0B5F-\\u0B61\\u0B66-\\u0B6F\\u0B71"
+ u"\\u0B82\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A"
+ u"\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BBE-"
+ u"\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCD\\u0BD0\\u0BD7\\u0BE6-\\u0BEF\\u0C01-"
+ u"\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D-"
+ u"\\u0C44\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C60\\u0C61\\u0C66-"
+ u"\\u0C6F\\u0C80\\u0C82\\u0C83\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8"
+ u"\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBC-\\u0CC4\\u0CC6-\\u0CC8\\u0CCA-\\u0CCD"
+ u"\\u0CD5\\u0CD6\\u0CE0-\\u0CE3\\u0CE6-\\u0CEF\\u0CF1\\u0CF2\\u0D00\\u0D02"
+ u"\\u0D03\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D-\\u0D43\\u0D46-"
+ u"\\u0D48\\u0D4A-\\u0D4E\\u0D54-\\u0D57\\u0D60\\u0D61\\u0D66-\\u0D6F\\u0D7A-"
+ u"\\u0D7F\\u0D82\\u0D83\\u0D85-\\u0D8E\\u0D91-\\u0D96\\u0D9A-\\u0DA5\\u0DA7-"
+ u"\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0DCA\\u0DCF-\\u0DD4\\u0DD6"
+ u"\\u0DD8-\\u0DDE\\u0DF2\\u0E01-\\u0E32\\u0E34-\\u0E3A\\u0E40-\\u0E4E\\u0E50-"
+ u"\\u0E59\\u0E81\\u0E82\\u0E84\\u0E86-\\u0E8A\\u0E8C-\\u0EA3\\u0EA5\\u0EA7-"
+ u"\\u0EB2\\u0EB4-\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EC8-\\u0ECD\\u0ED0-\\u0ED9"
+ u"\\u0EDE\\u0EDF\\u0F00\\u0F20-\\u0F29\\u0F35\\u0F37\\u0F3E-\\u0F42\\u0F44-"
+ u"\\u0F47\\u0F49-\\u0F4C\\u0F4E-\\u0F51\\u0F53-\\u0F56\\u0F58-\\u0F5B\\u0F5D-"
+ u"\\u0F68\\u0F6A-\\u0F6C\\u0F71\\u0F72\\u0F74\\u0F7A-\\u0F80\\u0F82-\\u0F84"
+ u"\\u0F86-\\u0F92\\u0F94-\\u0F97\\u0F99-\\u0F9C\\u0F9E-\\u0FA1\\u0FA3-\\u0FA6"
+ u"\\u0FA8-\\u0FAB\\u0FAD-\\u0FB8\\u0FBA-\\u0FBC\\u0FC6\\u1000-\\u1049\\u1050-"
+ u"\\u109D\\u10C7\\u10CD\\u10D0-\\u10F0\\u10F7-\\u10FA\\u10FD-\\u10FF\\u1200-"
+ u"\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288"
+ u"\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-"
+ u"\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u135D-"
+ u"\\u135F\\u1380-\\u138F\\u1780-\\u17A2\\u17A5-\\u17A7\\u17A9-\\u17B3\\u17B6-"
+ u"\\u17CA\\u17D2\\u17D7\\u17DC\\u17E0-\\u17E9\\u1C90-\\u1CBA\\u1CBD-\\u1CBF"
+ u"\\u1E00-\\u1E99\\u1E9E\\u1EA0-\\u1EF9\\u1F00-\\u1F15\\u1F18-\\u1F1D\\u1F20-"
+ u"\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F70"
+ u"\\u1F72\\u1F74\\u1F76\\u1F78\\u1F7A\\u1F7C\\u1F80-\\u1FB4\\u1FB6-\\u1FBA"
+ u"\\u1FBC\\u1FC2-\\u1FC4\\u1FC6-\\u1FC8\\u1FCA\\u1FCC\\u1FD0-\\u1FD2\\u1FD6-"
+ u"\\u1FDA\\u1FE0-\\u1FE2\\u1FE4-\\u1FEA\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FF8"
+ u"\\u1FFA\\u1FFC\\u2D27\\u2D2D\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE"
+ u"\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6"
+ u"\\u2DD8-\\u2DDE\\u3005-\\u3007\\u3041-\\u3096\\u3099\\u309A\\u309D\\u309E"
+ u"\\u30A1-\\u30FA\\u30FC-\\u30FE\\u3105-\\u312D\\u312F\\u31A0-\\u31BF\\u3400-"
+ u"\\u4DBF\\u4E00-\\u9FFC\\uA67F\\uA717-\\uA71F\\uA788\\uA78D\\uA792\\uA793"
+ u"\\uA7AA\\uA7AE\\uA7B8\\uA7B9\\uA7C2-\\uA7CA\\uA9E7-\\uA9FE\\uAA60-\\uAA76"
+ u"\\uAA7A-\\uAA7F\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26"
+ u"\\uAB28-\\uAB2E\\uAB66\\uAB67\\uAC00-\\uD7A3\\uFA0E\\uFA0F\\uFA11\\uFA13"
+ u"\\uFA14\\uFA1F\\uFA21\\uFA23\\uFA24\\uFA27-\\uFA29\\U00011301\\U00011303"
+ u"\\U0001133B\\U0001133C\\U00016FF0\\U00016FF1\\U0001B150-\\U0001B152"
+ u"\\U0001B164-\\U0001B167\\U00020000-\\U0002A6DD\\U0002A700-\\U0002B734"
+ u"\\U0002B740-\\U0002B81D\\U0002B820-\\U0002CEA1\\U0002CEB0-\\U0002EBE0"
+ u"\\U00030000-\\U0003134A]";
+
+ 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);
}
-} // namespace
-
+} // namespace
+
U_CFUNC void uspoof_internalInitStatics(UErrorCode *status) {
umtx_initOnce(gSpoofInitStaticsOnce, &initializeStatics, *status);
}
@@ -164,13 +164,13 @@ uspoof_open(UErrorCode *status) {
return NULL;
}
SpoofImpl *si = new SpoofImpl(*status);
- if (si == NULL) {
+ if (si == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
+ return NULL;
}
if (U_FAILURE(*status)) {
delete si;
- return NULL;
+ return NULL;
}
return si->asUSpoofChecker();
}
@@ -182,41 +182,41 @@ 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;
- }
-
+
+ if (data == NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+
umtx_initOnce(gSpoofInitStaticsOnce, &initializeStatics, *status);
- if (U_FAILURE(*status))
- {
- return NULL;
- }
-
+ if (U_FAILURE(*status))
+ {
+ return NULL;
+ }
+
SpoofData *sd = new SpoofData(data, length, *status);
- if (sd == NULL) {
- *status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
-
+ if (sd == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+
if (U_FAILURE(*status)) {
delete sd;
return NULL;
}
-
- SpoofImpl *si = new SpoofImpl(sd, *status);
- if (si == NULL) {
+
+ SpoofImpl *si = new SpoofImpl(sd, *status);
+ if (si == NULL) {
*status = U_MEMORY_ALLOCATION_ERROR;
- 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.
+ 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;
+ }
+
if (pActualLength != NULL) {
*pActualLength = sd->size();
}
@@ -231,10 +231,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 (result == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
if (U_FAILURE(*status)) {
delete result;
result = NULL;
@@ -350,7 +350,7 @@ uspoof_setAllowedUnicodeSet(USpoofChecker *sc, const UnicodeSet *chars, UErrorCo
*status = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
- UnicodeSet *clonedSet = chars->clone();
+ UnicodeSet *clonedSet = chars->clone();
if (clonedSet == NULL || clonedSet->isBogus()) {
*status = U_MEMORY_ALLOCATION_ERROR;
return;
@@ -423,7 +423,7 @@ uspoof_check2UTF8(const USpoofChecker *sc,
if (U_FAILURE(*status)) {
return 0;
}
- UnicodeString idStr = UnicodeString::fromUTF8(StringPiece(id, length>=0 ? length : static_cast<int32_t>(uprv_strlen(id))));
+ UnicodeString idStr = UnicodeString::fromUTF8(StringPiece(id, length>=0 ? length : static_cast<int32_t>(uprv_strlen(id))));
int32_t result = uspoof_check2UnicodeString(sc, idStr, checkResult, status);
return result;
}
@@ -462,8 +462,8 @@ uspoof_areConfusableUTF8(const USpoofChecker *sc,
*status = U_ILLEGAL_ARGUMENT_ERROR;
return 0;
}
- UnicodeString id1Str = UnicodeString::fromUTF8(StringPiece(id1, length1>=0? length1 : static_cast<int32_t>(uprv_strlen(id1))));
- UnicodeString id2Str = UnicodeString::fromUTF8(StringPiece(id2, length2>=0? length2 : static_cast<int32_t>(uprv_strlen(id2))));
+ UnicodeString id1Str = UnicodeString::fromUTF8(StringPiece(id1, length1>=0? length1 : static_cast<int32_t>(uprv_strlen(id1))));
+ UnicodeString id2Str = UnicodeString::fromUTF8(StringPiece(id2, length2>=0? length2 : static_cast<int32_t>(uprv_strlen(id2))));
int32_t results = uspoof_areConfusableUnicodeString(sc, id1Str, id2Str, status);
return results;
}
@@ -550,8 +550,8 @@ uspoof_checkUnicodeString(const USpoofChecker *sc,
return uspoof_check2UnicodeString(sc, id, NULL, status);
}
-namespace {
-
+namespace {
+
int32_t checkImpl(const SpoofImpl* This, const UnicodeString& id, CheckResult* checkResult, UErrorCode* status) {
U_ASSERT(This != NULL);
U_ASSERT(checkResult != NULL);
@@ -575,14 +575,14 @@ 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_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;
UChar32 c;
@@ -644,8 +644,8 @@ int32_t checkImpl(const SpoofImpl* This, const UnicodeString& id, CheckResult* c
return checkResult->toCombinedBitmask(This->fChecks);
}
-} // namespace
-
+} // namespace
+
U_CAPI int32_t U_EXPORT2
uspoof_check2UnicodeString(const USpoofChecker *sc,
const icu::UnicodeString &id,
@@ -740,7 +740,7 @@ uspoof_getSkeletonUTF8(const USpoofChecker *sc,
return 0;
}
- UnicodeString srcStr = UnicodeString::fromUTF8(StringPiece(id, length>=0 ? length : static_cast<int32_t>(uprv_strlen(id))));
+ UnicodeString srcStr = UnicodeString::fromUTF8(StringPiece(id, length>=0 ? length : static_cast<int32_t>(uprv_strlen(id))));
UnicodeString destStr;
uspoof_getSkeletonUnicodeString(sc, type, srcStr, destStr, status);
if (U_FAILURE(*status)) {
diff --git a/contrib/libs/icu/i18n/uspoof_build.cpp b/contrib/libs/icu/i18n/uspoof_build.cpp
index 192fb9a688..06f960bee1 100644
--- a/contrib/libs/icu/i18n/uspoof_build.cpp
+++ b/contrib/libs/icu/i18n/uspoof_build.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
***************************************************************************
@@ -6,7 +6,7 @@
* and others. All Rights Reserved.
***************************************************************************
* file name: uspoof_build.cpp
- * encoding: UTF-8
+ * encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
@@ -71,29 +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;
- }
+
+ 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;
- }
-
+ 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/contrib/libs/icu/i18n/uspoof_conf.cpp b/contrib/libs/icu/i18n/uspoof_conf.cpp
index 1a7cdad60a..cf81460226 100644
--- a/contrib/libs/icu/i18n/uspoof_conf.cpp
+++ b/contrib/libs/icu/i18n/uspoof_conf.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
@@ -8,7 +8,7 @@
*
******************************************************************************
* file name: uspoof_conf.cpp
-* encoding: UTF-8
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
@@ -76,10 +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;
- }
+ if (fVec == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
fHash = uhash_open(uhash_hashUnicodeString, // key hash function
uhash_compareUnicodeString, // Key Comparator
NULL, // Value Comparator
@@ -140,10 +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;
- }
+ if (hashedString == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
uhash_put(fHash, src, hashedString, &status);
fVec->addElement(hashedString, status);
}
@@ -168,32 +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();
- 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;
- }
-
+
+ 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;
- }
+ if (stringPool == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
}
@@ -425,7 +425,7 @@ void ConfusabledataBuilder::outputData(UErrorCode &status) {
for (i=0; i<numKeys; i++) {
int32_t key = fKeyVec->elementAti(i);
UChar32 codePoint = ConfusableDataUtils::keyToCodePoint(key);
- (void)previousCodePoint; // Suppress unused variable warning.
+ (void)previousCodePoint; // Suppress unused variable warning.
// strictly greater because there can be only one entry per code point
U_ASSERT(codePoint > previousCodePoint);
keys[i] = key;
diff --git a/contrib/libs/icu/i18n/uspoof_conf.h b/contrib/libs/icu/i18n/uspoof_conf.h
index cfa80e7ca7..ee5b6a970e 100644
--- a/contrib/libs/icu/i18n/uspoof_conf.h
+++ b/contrib/libs/icu/i18n/uspoof_conf.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
@@ -8,7 +8,7 @@
*
******************************************************************************
* file name: uspoof_conf.h
-* encoding: UTF-8
+* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
@@ -21,8 +21,8 @@
#ifndef __USPOOF_BUILDCONF_H__
#define __USPOOF_BUILDCONF_H__
-#include "unicode/utypes.h"
-
+#include "unicode/utypes.h"
+
#if !UCONFIG_NO_NORMALIZATION
#if !UCONFIG_NO_REGULAR_EXPRESSIONS
diff --git a/contrib/libs/icu/i18n/uspoof_impl.cpp b/contrib/libs/icu/i18n/uspoof_impl.cpp
index 88245b7f8f..fb8ff187c2 100644
--- a/contrib/libs/icu/i18n/uspoof_impl.cpp
+++ b/contrib/libs/icu/i18n/uspoof_impl.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
@@ -73,7 +73,7 @@ void SpoofImpl::construct(UErrorCode& status) {
// Copy Constructor, used by the user level clone() function.
SpoofImpl::SpoofImpl(const SpoofImpl &src, UErrorCode &status) :
- fChecks(USPOOF_ALL_CHECKS), fSpoofData(NULL), fAllowedCharsSet(NULL) ,
+ fChecks(USPOOF_ALL_CHECKS), fSpoofData(NULL), fAllowedCharsSet(NULL) ,
fAllowedLocales(NULL) {
if (U_FAILURE(status)) {
return;
@@ -82,7 +82,7 @@ SpoofImpl::SpoofImpl(const SpoofImpl &src, UErrorCode &status) :
if (src.fSpoofData != NULL) {
fSpoofData = src.fSpoofData->addReference();
}
- fAllowedCharsSet = src.fAllowedCharsSet->clone();
+ fAllowedCharsSet = src.fAllowedCharsSet->clone();
fAllowedLocales = uprv_strdup(src.fAllowedLocales);
if (fAllowedCharsSet == NULL || fAllowedLocales == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
@@ -100,7 +100,7 @@ SpoofImpl::~SpoofImpl() {
// Cast this instance as a USpoofChecker for the C API.
USpoofChecker *SpoofImpl::asUSpoofChecker() {
- return exportForC();
+ return exportForC();
}
//
@@ -108,7 +108,7 @@ USpoofChecker *SpoofImpl::asUSpoofChecker() {
// received from the C API.
//
const SpoofImpl *SpoofImpl::validateThis(const USpoofChecker *sc, UErrorCode &status) {
- auto* This = validate(sc, status);
+ auto* This = validate(sc, status);
if (U_FAILURE(status)) {
return NULL;
}
@@ -193,7 +193,7 @@ void SpoofImpl::setAllowedLocales(const char *localesList, UErrorCode &status) {
}
// Store the updated spoof checker state.
- tmpSet = allowedChars.clone();
+ tmpSet = allowedChars.clone();
const char *tmpLocalesList = uprv_strdup(localesList);
if (tmpSet == NULL || tmpLocalesList == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
@@ -365,45 +365,45 @@ 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; i<input.length();) {
- UChar32 cp = input.char32At(i);
- if (sawLeadCharacter && cp == 0x0307) {
- return i;
- }
- uint8_t combiningClass = u_getCombiningClass(cp);
- // Skip over characters except for those with combining class 0 (non-combining characters) or with
- // combining class 230 (same class as U+0307)
- U_ASSERT(u_getCombiningClass(0x0307) == 230);
- if (combiningClass == 0 || combiningClass == 230) {
- sawLeadCharacter = isIllegalCombiningDotLeadCharacter(cp);
- }
- i += U16_LENGTH(cp);
- }
- return -1;
-}
-
-static inline bool isIllegalCombiningDotLeadCharacterNoLookup(UChar32 cp) {
- return cp == u'i' || cp == u'j' || cp == u'ı' || cp == u'ȷ' || cp == u'l' ||
- u_hasBinaryProperty(cp, UCHAR_SOFT_DOTTED);
-}
-
-bool SpoofImpl::isIllegalCombiningDotLeadCharacter(UChar32 cp) const {
- if (isIllegalCombiningDotLeadCharacterNoLookup(cp)) {
- return true;
- }
- UnicodeString skelStr;
- fSpoofData->confusableLookup(cp, skelStr);
- UChar32 finalCp = skelStr.char32At(skelStr.moveIndex32(skelStr.length(), -1));
- if (finalCp != cp && isIllegalCombiningDotLeadCharacterNoLookup(finalCp)) {
- return true;
- }
- return false;
-}
-
-
-
+int32_t SpoofImpl::findHiddenOverlay(const UnicodeString& input, UErrorCode&) const {
+ bool sawLeadCharacter = false;
+ for (int32_t i=0; i<input.length();) {
+ UChar32 cp = input.char32At(i);
+ if (sawLeadCharacter && cp == 0x0307) {
+ return i;
+ }
+ uint8_t combiningClass = u_getCombiningClass(cp);
+ // Skip over characters except for those with combining class 0 (non-combining characters) or with
+ // combining class 230 (same class as U+0307)
+ U_ASSERT(u_getCombiningClass(0x0307) == 230);
+ if (combiningClass == 0 || combiningClass == 230) {
+ sawLeadCharacter = isIllegalCombiningDotLeadCharacter(cp);
+ }
+ i += U16_LENGTH(cp);
+ }
+ return -1;
+}
+
+static inline bool isIllegalCombiningDotLeadCharacterNoLookup(UChar32 cp) {
+ return cp == u'i' || cp == u'j' || cp == u'ı' || cp == u'ȷ' || cp == u'l' ||
+ u_hasBinaryProperty(cp, UCHAR_SOFT_DOTTED);
+}
+
+bool SpoofImpl::isIllegalCombiningDotLeadCharacter(UChar32 cp) const {
+ if (isIllegalCombiningDotLeadCharacterNoLookup(cp)) {
+ return true;
+ }
+ UnicodeString skelStr;
+ fSpoofData->confusableLookup(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.
// Input: UChar *string text. Output: a UChar32
// Input has been pre-checked, and will have no non-hex chars.
@@ -442,12 +442,12 @@ UChar32 SpoofImpl::ScanHex(const UChar *s, int32_t start, int32_t limit, UErrorC
//
//-----------------------------------------
-CheckResult::CheckResult() {
+CheckResult::CheckResult() {
clear();
}
USpoofCheckResult* CheckResult::asUSpoofCheckResult() {
- return exportForC();
+ return exportForC();
}
//
@@ -455,11 +455,11 @@ USpoofCheckResult* CheckResult::asUSpoofCheckResult() {
// received from the C API.
//
const CheckResult* CheckResult::validateThis(const USpoofCheckResult *ptr, UErrorCode &status) {
- return validate(ptr, status);
+ return validate(ptr, status);
}
CheckResult* CheckResult::validateThis(USpoofCheckResult *ptr, UErrorCode &status) {
- return validate(ptr, status);
+ return validate(ptr, status);
}
void CheckResult::clear() {
@@ -546,25 +546,25 @@ uspoof_cleanupDefaultData(void) {
if (gDefaultSpoofData) {
// Will delete, assuming all user-level spoof checkers were closed.
gDefaultSpoofData->removeReference();
- gDefaultSpoofData = nullptr;
+ gDefaultSpoofData = nullptr;
gSpoofInitDefaultOnce.reset();
}
return TRUE;
}
static void U_CALLCONV uspoof_loadDefaultData(UErrorCode& status) {
- UDataMemory *udm = udata_openChoice(nullptr, "cfu", "confusables",
+ UDataMemory *udm = udata_openChoice(nullptr, "cfu", "confusables",
spoofDataIsAcceptable,
- nullptr, // 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;
+ gDefaultSpoofData = nullptr;
return;
}
- if (gDefaultSpoofData == nullptr) {
+ if (gDefaultSpoofData == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
@@ -605,10 +605,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;
- }
+ if (data == NULL) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
void *ncData = const_cast<void *>(data);
fRawData = static_cast<SpoofDataHeader *>(ncData);
if (length < fRawData->fLength) {
@@ -729,7 +729,7 @@ void *SpoofData::reserveSpace(int32_t numBytes, UErrorCode &status) {
return NULL;
}
if (!fDataOwned) {
- UPRV_UNREACHABLE;
+ UPRV_UNREACHABLE;
}
numBytes = (numBytes + 15) & ~15; // Round up to a multiple of 16
diff --git a/contrib/libs/icu/i18n/uspoof_impl.h b/contrib/libs/icu/i18n/uspoof_impl.h
index b111d4b16a..398dec71ef 100644
--- a/contrib/libs/icu/i18n/uspoof_impl.h
+++ b/contrib/libs/icu/i18n/uspoof_impl.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
***************************************************************************
@@ -20,15 +20,15 @@
#include "unicode/uspoof.h"
#include "unicode/uscript.h"
#include "unicode/udata.h"
-#include "udataswp.h"
+#include "udataswp.h"
#include "utrie2.h"
#if !UCONFIG_NO_NORMALIZATION
#ifdef __cplusplus
-#include "capi_helper.h"
-
+#include "capi_helper.h"
+
U_NAMESPACE_BEGIN
// The maximium length (in UTF-16 UChars) of the skeleton replacement string resulting from
@@ -54,8 +54,8 @@ class ConfusableDataUtils;
* Class SpoofImpl corresponds directly to the plain C API opaque type
* USpoofChecker. One can be cast to the other.
*/
-class SpoofImpl : public UObject,
- public IcuCApiHelper<USpoofChecker, SpoofImpl, USPOOF_MAGIC> {
+class SpoofImpl : public UObject,
+ public IcuCApiHelper<USpoofChecker, SpoofImpl, USPOOF_MAGIC> {
public:
SpoofImpl(SpoofData *data, UErrorCode& status);
SpoofImpl(UErrorCode& status);
@@ -86,9 +86,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;
-
+ 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);
@@ -114,8 +114,8 @@ public:
* Class CheckResult corresponds directly to the plain C API opaque type
* USpoofCheckResult. One can be cast to the other.
*/
-class CheckResult : public UObject,
- public IcuCApiHelper<USpoofCheckResult, CheckResult, USPOOF_CHECK_MAGIC> {
+class CheckResult : public UObject,
+ public IcuCApiHelper<USpoofCheckResult, CheckResult, USPOOF_CHECK_MAGIC> {
public:
CheckResult();
virtual ~CheckResult();
diff --git a/contrib/libs/icu/i18n/usrchimp.h b/contrib/libs/icu/i18n/usrchimp.h
index 88b2e217db..6d5d0a56f2 100644
--- a/contrib/libs/icu/i18n/usrchimp.h
+++ b/contrib/libs/icu/i18n/usrchimp.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
diff --git a/contrib/libs/icu/i18n/utf16collationiterator.cpp b/contrib/libs/icu/i18n/utf16collationiterator.cpp
index 7598b0ee52..c8444432c4 100644
--- a/contrib/libs/icu/i18n/utf16collationiterator.cpp
+++ b/contrib/libs/icu/i18n/utf16collationiterator.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/utf16collationiterator.h b/contrib/libs/icu/i18n/utf16collationiterator.h
index fd3a05e9ef..af91969533 100644
--- a/contrib/libs/icu/i18n/utf16collationiterator.h
+++ b/contrib/libs/icu/i18n/utf16collationiterator.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/utf8collationiterator.cpp b/contrib/libs/icu/i18n/utf8collationiterator.cpp
index 345b1994ef..a994657647 100644
--- a/contrib/libs/icu/i18n/utf8collationiterator.cpp
+++ b/contrib/libs/icu/i18n/utf8collationiterator.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -49,21 +49,21 @@ UTF8CollationIterator::handleNextCE32(UChar32 &c, UErrorCode & /*errorCode*/) {
}
// Optimized combination of U8_NEXT_OR_FFFD() and UTRIE2_U8_NEXT32().
c = u8[pos++];
- if(U8_IS_SINGLE(c)) {
- // ASCII 00..7F
+ if(U8_IS_SINGLE(c)) {
+ // ASCII 00..7F
return trie->data32[c];
}
uint8_t t1, t2;
- if(0xe0 <= c && c < 0xf0 &&
- ((pos + 1) < length || length < 0) &&
- U8_IS_VALID_LEAD3_AND_T1(c, t1 = u8[pos]) &&
- (t2 = (u8[pos + 1] - 0x80)) <= 0x3f) {
- // U+0800..U+FFFF except surrogates
- c = (((c & 0xf) << 12) | ((t1 & 0x3f) << 6) | t2);
- pos += 2;
- return UTRIE2_GET32_FROM_U16_SINGLE_LEAD(trie, c);
- } else if(c < 0xe0 && c >= 0xc2 && pos != length && (t1 = (u8[pos] - 0x80)) <= 0x3f) {
- // U+0080..U+07FF
+ if(0xe0 <= c && c < 0xf0 &&
+ ((pos + 1) < length || length < 0) &&
+ U8_IS_VALID_LEAD3_AND_T1(c, t1 = u8[pos]) &&
+ (t2 = (u8[pos + 1] - 0x80)) <= 0x3f) {
+ // U+0800..U+FFFF except surrogates
+ c = (((c & 0xf) << 12) | ((t1 & 0x3f) << 6) | t2);
+ pos += 2;
+ return UTRIE2_GET32_FROM_U16_SINGLE_LEAD(trie, c);
+ } else if(c < 0xe0 && c >= 0xc2 && pos != length && (t1 = (u8[pos] - 0x80)) <= 0x3f) {
+ // U+0080..U+07FF
uint32_t ce32 = trie->data32[trie->index[(UTRIE2_UTF8_2B_INDEX_2_OFFSET - 0xc0) + c] + t1];
c = ((c & 0x1f) << 6) | t1;
++pos;
@@ -157,27 +157,27 @@ FCDUTF8CollationIterator::handleNextCE32(UChar32 &c, UErrorCode &errorCode) {
return Collation::FALLBACK_CE32;
}
c = u8[pos++];
- if(U8_IS_SINGLE(c)) {
- // ASCII 00..7F
+ if(U8_IS_SINGLE(c)) {
+ // ASCII 00..7F
return trie->data32[c];
}
uint8_t t1, t2;
- if(0xe0 <= c && c < 0xf0 &&
- ((pos + 1) < length || length < 0) &&
- U8_IS_VALID_LEAD3_AND_T1(c, t1 = u8[pos]) &&
- (t2 = (u8[pos + 1] - 0x80)) <= 0x3f) {
- // U+0800..U+FFFF except surrogates
- c = (((c & 0xf) << 12) | ((t1 & 0x3f) << 6) | t2);
- pos += 2;
- if(CollationFCD::hasTccc(c) &&
- (CollationFCD::maybeTibetanCompositeVowel(c) ||
- (pos != length && nextHasLccc()))) {
- pos -= 3;
- } else {
- break; // return CE32(BMP)
- }
- } else if(c < 0xe0 && c >= 0xc2 && pos != length && (t1 = (u8[pos] - 0x80)) <= 0x3f) {
- // U+0080..U+07FF
+ if(0xe0 <= c && c < 0xf0 &&
+ ((pos + 1) < length || length < 0) &&
+ U8_IS_VALID_LEAD3_AND_T1(c, t1 = u8[pos]) &&
+ (t2 = (u8[pos + 1] - 0x80)) <= 0x3f) {
+ // U+0800..U+FFFF except surrogates
+ c = (((c & 0xf) << 12) | ((t1 & 0x3f) << 6) | t2);
+ pos += 2;
+ if(CollationFCD::hasTccc(c) &&
+ (CollationFCD::maybeTibetanCompositeVowel(c) ||
+ (pos != length && nextHasLccc()))) {
+ pos -= 3;
+ } else {
+ break; // return CE32(BMP)
+ }
+ } else if(c < 0xe0 && c >= 0xc2 && pos != length && (t1 = (u8[pos] - 0x80)) <= 0x3f) {
+ // U+0080..U+07FF
uint32_t ce32 = trie->data32[trie->index[(UTRIE2_UTF8_2B_INDEX_2_OFFSET - 0xc0) + c] + t1];
c = ((c & 0x1f) << 6) | t1;
++pos;
@@ -235,7 +235,7 @@ UBool
FCDUTF8CollationIterator::previousHasTccc() const {
U_ASSERT(state == CHECK_BWD && pos != 0);
UChar32 c = u8[pos - 1];
- if(U8_IS_SINGLE(c)) { return FALSE; }
+ if(U8_IS_SINGLE(c)) { return FALSE; }
int32_t i = pos;
U8_PREV_OR_FFFD(u8, 0, i, c);
if(c > 0xffff) { c = U16_LEAD(c); }
@@ -269,7 +269,7 @@ FCDUTF8CollationIterator::nextCodePoint(UErrorCode &errorCode) {
if(pos == length || ((c = u8[pos]) == 0 && length < 0)) {
return U_SENTINEL;
}
- if(U8_IS_SINGLE(c)) {
+ if(U8_IS_SINGLE(c)) {
++pos;
return c;
}
@@ -307,7 +307,7 @@ FCDUTF8CollationIterator::previousCodePoint(UErrorCode &errorCode) {
if(pos == 0) {
return U_SENTINEL;
}
- if(U8_IS_SINGLE(c = u8[pos - 1])) {
+ if(U8_IS_SINGLE(c = u8[pos - 1])) {
--pos;
return c;
}
diff --git a/contrib/libs/icu/i18n/utf8collationiterator.h b/contrib/libs/icu/i18n/utf8collationiterator.h
index 9a3ec45aeb..32938feb2b 100644
--- a/contrib/libs/icu/i18n/utf8collationiterator.h
+++ b/contrib/libs/icu/i18n/utf8collationiterator.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/utmscale.cpp b/contrib/libs/icu/i18n/utmscale.cpp
index 7bf6eec331..a6a40c7dfd 100644
--- a/contrib/libs/icu/i18n/utmscale.cpp
+++ b/contrib/libs/icu/i18n/utmscale.cpp
@@ -1,116 +1,116 @@
-// © 2016 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html
-/*
-*******************************************************************************
-* Copyright (C) 2004-2012, International Business Machines Corporation and
-* others. All Rights Reserved.
-*******************************************************************************
-*/
-
-#include "unicode/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/utmscale.h"
-
-#define ticks INT64_C(1)
-#define microseconds (ticks * 10)
-#define milliseconds (microseconds * 1000)
-#define seconds (milliseconds * 1000)
-#define minutes (seconds * 60)
-#define hours (minutes * 60)
-#define days (hours * 24)
-
-/* Constants generated by ICU4J com.ibm.icu.dev.tool.timescale.GenerateCTimeScaleData. */
-static const int64_t timeScaleTable[UDTS_MAX_SCALE][UTSV_MAX_SCALE_VALUE] = {
- /* units epochOffset fromMin fromMax toMin toMax epochOffsetP1 epochOffsetM1 unitsRound minRound maxRound */
- {milliseconds, INT64_C(62135596800000), INT64_C(-984472800485477), INT64_C(860201606885477), INT64_C(-9223372036854774999), INT64_C(9223372036854774999), INT64_C(62135596800001), INT64_C(62135596799999), INT64_C(5000), INT64_C(-9223372036854770808), INT64_C(9223372036854770807)},
- {seconds, INT64_C(62135596800), INT64_C(-984472800485), INT64_C(860201606885), U_INT64_MIN, U_INT64_MAX, INT64_C(62135596801), INT64_C(62135596799), INT64_C(5000000), INT64_C(-9223372036849775808), INT64_C(9223372036849775807)},
- {milliseconds, INT64_C(62135596800000), INT64_C(-984472800485477), INT64_C(860201606885477), INT64_C(-9223372036854774999), INT64_C(9223372036854774999), INT64_C(62135596800001), INT64_C(62135596799999), INT64_C(5000), INT64_C(-9223372036854770808), INT64_C(9223372036854770807)},
- {ticks, INT64_C(504911232000000000), U_INT64_MIN, INT64_C(8718460804854775807), INT64_C(-8718460804854775808), U_INT64_MAX, INT64_C(504911232000000000), INT64_C(504911232000000000), INT64_C(0), U_INT64_MIN, U_INT64_MAX},
- {ticks, INT64_C(0), U_INT64_MIN, U_INT64_MAX, U_INT64_MIN, U_INT64_MAX, INT64_C(0), INT64_C(0), INT64_C(0), U_INT64_MIN, U_INT64_MAX},
- {seconds, INT64_C(60052752000), INT64_C(-982389955685), INT64_C(862284451685), U_INT64_MIN, U_INT64_MAX, INT64_C(60052752001), INT64_C(60052751999), INT64_C(5000000), INT64_C(-9223372036849775808), INT64_C(9223372036849775807)},
- {seconds, INT64_C(63113904000), INT64_C(-985451107685), INT64_C(859223299685), U_INT64_MIN, U_INT64_MAX, INT64_C(63113904001), INT64_C(63113903999), INT64_C(5000000), INT64_C(-9223372036849775808), INT64_C(9223372036849775807)},
- {days, INT64_C(693594), INT64_C(-11368793), INT64_C(9981605), U_INT64_MIN, U_INT64_MAX, INT64_C(693595), INT64_C(693593), INT64_C(432000000000), INT64_C(-9223371604854775808), INT64_C(9223371604854775807)},
- {days, INT64_C(693594), INT64_C(-11368793), INT64_C(9981605), U_INT64_MIN, U_INT64_MAX, INT64_C(693595), INT64_C(693593), INT64_C(432000000000), INT64_C(-9223371604854775808), INT64_C(9223371604854775807)},
- {microseconds, INT64_C(62135596800000000), INT64_C(-984472800485477580), INT64_C(860201606885477580), INT64_C(-9223372036854775804), INT64_C(9223372036854775804), INT64_C(62135596800000001), INT64_C(62135596799999999), INT64_C(5), INT64_C(-9223372036854775803), INT64_C(9223372036854775802)},
-};
-
-U_CAPI int64_t U_EXPORT2
-utmscale_getTimeScaleValue(UDateTimeScale timeScale, UTimeScaleValue value, UErrorCode *status)
-{
- if (status == NULL || U_FAILURE(*status)) {
- return 0;
- }
-
- if (timeScale < UDTS_JAVA_TIME || UDTS_MAX_SCALE <= timeScale
- || value < UTSV_UNITS_VALUE || UTSV_MAX_SCALE_VALUE <= value)
- {
- *status = U_ILLEGAL_ARGUMENT_ERROR;
- return 0;
- }
-
- return timeScaleTable[timeScale][value];
-}
-
-U_CAPI int64_t U_EXPORT2
-utmscale_fromInt64(int64_t otherTime, UDateTimeScale timeScale, UErrorCode *status)
-{
- const int64_t *data;
-
- if (status == NULL || U_FAILURE(*status)) {
- return 0;
- }
-
- if ((int32_t)timeScale < 0 || timeScale >= UDTS_MAX_SCALE) {
- *status = U_ILLEGAL_ARGUMENT_ERROR;
- return 0;
- }
-
- data = (const int64_t *)(&timeScaleTable[timeScale]);
-
- if (otherTime < data[UTSV_FROM_MIN_VALUE] || otherTime > data[UTSV_FROM_MAX_VALUE]) {
- *status = U_ILLEGAL_ARGUMENT_ERROR;
- return 0;
- }
-
- return (otherTime + data[UTSV_EPOCH_OFFSET_VALUE]) * data[UTSV_UNITS_VALUE];
-}
-
-U_CAPI int64_t U_EXPORT2
-utmscale_toInt64(int64_t universalTime, UDateTimeScale timeScale, UErrorCode *status)
-{
- const int64_t *data;
-
- if (status == NULL || U_FAILURE(*status)) {
- return 0;
- }
-
- if ((int32_t)timeScale < 0 || timeScale >= UDTS_MAX_SCALE) {
- *status = U_ILLEGAL_ARGUMENT_ERROR;
- return 0;
- }
-
- data = (const int64_t *)(&timeScaleTable[timeScale]);
-
- if (universalTime < data[UTSV_TO_MIN_VALUE] || universalTime > data[UTSV_TO_MAX_VALUE]) {
- *status = U_ILLEGAL_ARGUMENT_ERROR;
- return 0;
- }
-
- if (universalTime < 0) {
- if (universalTime < data[UTSV_MIN_ROUND_VALUE]) {
- return (universalTime + data[UTSV_UNITS_ROUND_VALUE]) / data[UTSV_UNITS_VALUE] - data[UTSV_EPOCH_OFFSET_PLUS_1_VALUE];
- }
-
- return (universalTime - data[UTSV_UNITS_ROUND_VALUE]) / data[UTSV_UNITS_VALUE] - data[UTSV_EPOCH_OFFSET_VALUE];
- }
-
- if (universalTime > data[UTSV_MAX_ROUND_VALUE]) {
- return (universalTime - data[UTSV_UNITS_ROUND_VALUE]) / data[UTSV_UNITS_VALUE] - data[UTSV_EPOCH_OFFSET_MINUS_1_VALUE];
- }
-
- return (universalTime + data[UTSV_UNITS_ROUND_VALUE]) / data[UTSV_UNITS_VALUE] - data[UTSV_EPOCH_OFFSET_VALUE];
-}
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+*******************************************************************************
+* Copyright (C) 2004-2012, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/utmscale.h"
+
+#define ticks INT64_C(1)
+#define microseconds (ticks * 10)
+#define milliseconds (microseconds * 1000)
+#define seconds (milliseconds * 1000)
+#define minutes (seconds * 60)
+#define hours (minutes * 60)
+#define days (hours * 24)
+
+/* Constants generated by ICU4J com.ibm.icu.dev.tool.timescale.GenerateCTimeScaleData. */
+static const int64_t timeScaleTable[UDTS_MAX_SCALE][UTSV_MAX_SCALE_VALUE] = {
+ /* units epochOffset fromMin fromMax toMin toMax epochOffsetP1 epochOffsetM1 unitsRound minRound maxRound */
+ {milliseconds, INT64_C(62135596800000), INT64_C(-984472800485477), INT64_C(860201606885477), INT64_C(-9223372036854774999), INT64_C(9223372036854774999), INT64_C(62135596800001), INT64_C(62135596799999), INT64_C(5000), INT64_C(-9223372036854770808), INT64_C(9223372036854770807)},
+ {seconds, INT64_C(62135596800), INT64_C(-984472800485), INT64_C(860201606885), U_INT64_MIN, U_INT64_MAX, INT64_C(62135596801), INT64_C(62135596799), INT64_C(5000000), INT64_C(-9223372036849775808), INT64_C(9223372036849775807)},
+ {milliseconds, INT64_C(62135596800000), INT64_C(-984472800485477), INT64_C(860201606885477), INT64_C(-9223372036854774999), INT64_C(9223372036854774999), INT64_C(62135596800001), INT64_C(62135596799999), INT64_C(5000), INT64_C(-9223372036854770808), INT64_C(9223372036854770807)},
+ {ticks, INT64_C(504911232000000000), U_INT64_MIN, INT64_C(8718460804854775807), INT64_C(-8718460804854775808), U_INT64_MAX, INT64_C(504911232000000000), INT64_C(504911232000000000), INT64_C(0), U_INT64_MIN, U_INT64_MAX},
+ {ticks, INT64_C(0), U_INT64_MIN, U_INT64_MAX, U_INT64_MIN, U_INT64_MAX, INT64_C(0), INT64_C(0), INT64_C(0), U_INT64_MIN, U_INT64_MAX},
+ {seconds, INT64_C(60052752000), INT64_C(-982389955685), INT64_C(862284451685), U_INT64_MIN, U_INT64_MAX, INT64_C(60052752001), INT64_C(60052751999), INT64_C(5000000), INT64_C(-9223372036849775808), INT64_C(9223372036849775807)},
+ {seconds, INT64_C(63113904000), INT64_C(-985451107685), INT64_C(859223299685), U_INT64_MIN, U_INT64_MAX, INT64_C(63113904001), INT64_C(63113903999), INT64_C(5000000), INT64_C(-9223372036849775808), INT64_C(9223372036849775807)},
+ {days, INT64_C(693594), INT64_C(-11368793), INT64_C(9981605), U_INT64_MIN, U_INT64_MAX, INT64_C(693595), INT64_C(693593), INT64_C(432000000000), INT64_C(-9223371604854775808), INT64_C(9223371604854775807)},
+ {days, INT64_C(693594), INT64_C(-11368793), INT64_C(9981605), U_INT64_MIN, U_INT64_MAX, INT64_C(693595), INT64_C(693593), INT64_C(432000000000), INT64_C(-9223371604854775808), INT64_C(9223371604854775807)},
+ {microseconds, INT64_C(62135596800000000), INT64_C(-984472800485477580), INT64_C(860201606885477580), INT64_C(-9223372036854775804), INT64_C(9223372036854775804), INT64_C(62135596800000001), INT64_C(62135596799999999), INT64_C(5), INT64_C(-9223372036854775803), INT64_C(9223372036854775802)},
+};
+
+U_CAPI int64_t U_EXPORT2
+utmscale_getTimeScaleValue(UDateTimeScale timeScale, UTimeScaleValue value, UErrorCode *status)
+{
+ if (status == NULL || U_FAILURE(*status)) {
+ return 0;
+ }
+
+ if (timeScale < UDTS_JAVA_TIME || UDTS_MAX_SCALE <= timeScale
+ || value < UTSV_UNITS_VALUE || UTSV_MAX_SCALE_VALUE <= value)
+ {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ return timeScaleTable[timeScale][value];
+}
+
+U_CAPI int64_t U_EXPORT2
+utmscale_fromInt64(int64_t otherTime, UDateTimeScale timeScale, UErrorCode *status)
+{
+ const int64_t *data;
+
+ if (status == NULL || U_FAILURE(*status)) {
+ return 0;
+ }
+
+ if ((int32_t)timeScale < 0 || timeScale >= UDTS_MAX_SCALE) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ data = (const int64_t *)(&timeScaleTable[timeScale]);
+
+ if (otherTime < data[UTSV_FROM_MIN_VALUE] || otherTime > data[UTSV_FROM_MAX_VALUE]) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ return (otherTime + data[UTSV_EPOCH_OFFSET_VALUE]) * data[UTSV_UNITS_VALUE];
+}
+
+U_CAPI int64_t U_EXPORT2
+utmscale_toInt64(int64_t universalTime, UDateTimeScale timeScale, UErrorCode *status)
+{
+ const int64_t *data;
+
+ if (status == NULL || U_FAILURE(*status)) {
+ return 0;
+ }
+
+ if ((int32_t)timeScale < 0 || timeScale >= UDTS_MAX_SCALE) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ data = (const int64_t *)(&timeScaleTable[timeScale]);
+
+ if (universalTime < data[UTSV_TO_MIN_VALUE] || universalTime > data[UTSV_TO_MAX_VALUE]) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ if (universalTime < 0) {
+ if (universalTime < data[UTSV_MIN_ROUND_VALUE]) {
+ return (universalTime + data[UTSV_UNITS_ROUND_VALUE]) / data[UTSV_UNITS_VALUE] - data[UTSV_EPOCH_OFFSET_PLUS_1_VALUE];
+ }
+
+ return (universalTime - data[UTSV_UNITS_ROUND_VALUE]) / data[UTSV_UNITS_VALUE] - data[UTSV_EPOCH_OFFSET_VALUE];
+ }
+
+ if (universalTime > data[UTSV_MAX_ROUND_VALUE]) {
+ return (universalTime - data[UTSV_UNITS_ROUND_VALUE]) / data[UTSV_UNITS_VALUE] - data[UTSV_EPOCH_OFFSET_MINUS_1_VALUE];
+ }
+
+ return (universalTime + data[UTSV_UNITS_ROUND_VALUE]) / data[UTSV_UNITS_VALUE] - data[UTSV_EPOCH_OFFSET_VALUE];
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/contrib/libs/icu/i18n/utrans.cpp b/contrib/libs/icu/i18n/utrans.cpp
index 29013ead12..8b1ae16992 100644
--- a/contrib/libs/icu/i18n/utrans.cpp
+++ b/contrib/libs/icu/i18n/utrans.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -41,12 +41,12 @@ U_NAMESPACE_BEGIN
class ReplaceableGlue : public Replaceable {
UReplaceable *rep;
- const UReplaceableCallbacks *func;
+ const UReplaceableCallbacks *func;
public:
ReplaceableGlue(UReplaceable *replaceable,
- const UReplaceableCallbacks *funcCallback);
+ const UReplaceableCallbacks *funcCallback);
virtual ~ReplaceableGlue();
@@ -88,7 +88,7 @@ protected:
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ReplaceableGlue)
ReplaceableGlue::ReplaceableGlue(UReplaceable *replaceable,
- const UReplaceableCallbacks *funcCallback)
+ const UReplaceableCallbacks *funcCallback)
: Replaceable()
{
this->rep = replaceable;
@@ -398,7 +398,7 @@ utrans_openIDs(UErrorCode *pErrorCode) {
U_CAPI void U_EXPORT2
utrans_trans(const UTransliterator* trans,
UReplaceable* rep,
- const UReplaceableCallbacks* repFunc,
+ const UReplaceableCallbacks* repFunc,
int32_t start,
int32_t* limit,
UErrorCode* status) {
@@ -418,7 +418,7 @@ utrans_trans(const UTransliterator* trans,
U_CAPI void U_EXPORT2
utrans_transIncremental(const UTransliterator* trans,
UReplaceable* rep,
- const UReplaceableCallbacks* repFunc,
+ const UReplaceableCallbacks* repFunc,
UTransPosition* pos,
UErrorCode* status) {
diff --git a/contrib/libs/icu/i18n/vtzone.cpp b/contrib/libs/icu/i18n/vtzone.cpp
index 36e5834523..b9d6620395 100644
--- a/contrib/libs/icu/i18n/vtzone.cpp
+++ b/contrib/libs/icu/i18n/vtzone.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -135,7 +135,7 @@ static UnicodeString& appendAsciiDigits(int32_t number, uint8_t length, UnicodeS
digits[i++] = number % 10;
number /= 10;
} while (number != 0);
- length = static_cast<uint8_t>(i);
+ length = static_cast<uint8_t>(i);
} else {
// fixed digits
for (i = 0; i < length; i++) {
@@ -358,7 +358,7 @@ static void millisToOffset(int32_t millis, UnicodeString& str) {
/*
* Create a default TZNAME from TZID
*/
-static void getDefaultTZName(const UnicodeString &tzid, UBool isDST, UnicodeString& zonename) {
+static void getDefaultTZName(const UnicodeString &tzid, UBool isDST, UnicodeString& zonename) {
zonename = tzid;
if (isDST) {
zonename += UNICODE_STRING_SIMPLE("(DST)");
@@ -526,15 +526,15 @@ rruleParseError:
static TimeZoneRule* createRuleByRRULE(const UnicodeString& zonename, int rawOffset, int dstSavings, UDate start,
UVector* dates, int fromOffset, UErrorCode& status) {
if (U_FAILURE(status)) {
- return nullptr;
+ return nullptr;
}
- if (dates == nullptr || dates->size() == 0) {
+ if (dates == nullptr || dates->size() == 0) {
status = U_ILLEGAL_ARGUMENT_ERROR;
- return nullptr;
+ return nullptr;
}
int32_t i, j;
- DateTimeRule *adtr = nullptr;
+ DateTimeRule *adtr = nullptr;
// Parse the first rule
UnicodeString rrule = *((UnicodeString*)dates->elementAt(0));
@@ -545,7 +545,7 @@ static TimeZoneRule* createRuleByRRULE(const UnicodeString& zonename, int rawOff
parseRRULE(rrule, month, dayOfWeek, nthDayOfWeek, days, daysCount, until, status);
if (U_FAILURE(status)) {
- return nullptr;
+ return nullptr;
}
if (dates->size() == 1) {
@@ -620,7 +620,7 @@ static TimeZoneRule* createRuleByRRULE(const UnicodeString& zonename, int rawOff
int32_t tmp_daysCount = UPRV_LENGTHOF(tmp_days);
parseRRULE(rrule, tmp_month, tmp_dayOfWeek, tmp_nthDayOfWeek, tmp_days, tmp_daysCount, tmp_until, status);
if (U_FAILURE(status)) {
- return nullptr;
+ return nullptr;
}
// If UNTIL is newer than previous one, use the one
if (tmp_until > until) {
@@ -713,14 +713,14 @@ static TimeZoneRule* createRuleByRRULE(const UnicodeString& zonename, int rawOff
// first Sunday after 15th day in the month
adtr = new DateTimeRule(month, dayOfMonth, dayOfWeek, TRUE, startMID, DateTimeRule::WALL_TIME);
}
- if (adtr == nullptr) {
+ if (adtr == nullptr) {
goto unsupportedRRule;
}
return new AnnualTimeZoneRule(zonename, rawOffset, dstSavings, adtr, startYear, endYear);
unsupportedRRule:
status = U_INVALID_STATE_ERROR;
- return nullptr;
+ return nullptr;
}
/*
@@ -729,35 +729,35 @@ unsupportedRRule:
static TimeZoneRule* createRuleByRDATE(const UnicodeString& zonename, int32_t rawOffset, int32_t dstSavings,
UDate start, UVector* dates, int32_t fromOffset, UErrorCode& status) {
if (U_FAILURE(status)) {
- return nullptr;
+ return nullptr;
}
- TimeArrayTimeZoneRule *retVal = nullptr;
- if (dates == nullptr || dates->size() == 0) {
+ TimeArrayTimeZoneRule *retVal = nullptr;
+ if (dates == nullptr || dates->size() == 0) {
// When no RDATE line is provided, use start (DTSTART)
// as the transition time
- retVal = new TimeArrayTimeZoneRule(zonename, rawOffset, dstSavings, &start, 1, DateTimeRule::UTC_TIME);
+ retVal = new TimeArrayTimeZoneRule(zonename, rawOffset, dstSavings, &start, 1, DateTimeRule::UTC_TIME);
} else {
// Create an array of transition times
int32_t size = dates->size();
UDate* times = (UDate*)uprv_malloc(sizeof(UDate) * size);
- if (times == nullptr) {
+ if (times == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
+ return nullptr;
}
for (int32_t i = 0; i < size; i++) {
UnicodeString *datestr = (UnicodeString*)dates->elementAt(i);
times[i] = parseDateTimeString(*datestr, fromOffset, status);
if (U_FAILURE(status)) {
uprv_free(times);
- return nullptr;
+ return nullptr;
}
}
- retVal = new TimeArrayTimeZoneRule(zonename, rawOffset, dstSavings, times, size, DateTimeRule::UTC_TIME);
+ retVal = new TimeArrayTimeZoneRule(zonename, rawOffset, dstSavings, times, size, DateTimeRule::UTC_TIME);
uprv_free(times);
}
- if (retVal == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
+ if (retVal == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
return retVal;
}
@@ -801,15 +801,15 @@ static UBool isEquivalentDateRule(int32_t month, int32_t weekInMonth, int32_t da
/*
* Convert the rule to its equivalent rule using WALL_TIME mode.
- * This function returns nullptr when the specified DateTimeRule is already
+ * This function returns nullptr when the specified DateTimeRule is already
* using WALL_TIME mode.
*/
-static DateTimeRule *toWallTimeRule(const DateTimeRule *rule, int32_t rawOffset, int32_t dstSavings, UErrorCode &status) {
- if (U_FAILURE(status)) {
- return nullptr;
- }
+static DateTimeRule *toWallTimeRule(const DateTimeRule *rule, int32_t rawOffset, int32_t dstSavings, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
if (rule->getTimeRuleType() == DateTimeRule::WALL_TIME) {
- return nullptr;
+ return nullptr;
}
int32_t wallt = rule->getRuleMillisInDay();
if (rule->getTimeRuleType() == DateTimeRule::UTC_TIME) {
@@ -868,15 +868,15 @@ static DateTimeRule *toWallTimeRule(const DateTimeRule *rule, int32_t rawOffset,
}
}
// Create a new rule
- DateTimeRule *modifiedRule = nullptr;
+ DateTimeRule *modifiedRule = nullptr;
if (dtype == DateTimeRule::DOM) {
modifiedRule = new DateTimeRule(month, dom, wallt, DateTimeRule::WALL_TIME);
} else {
- modifiedRule = new DateTimeRule(month, dom, dow, (dtype == DateTimeRule::DOW_GEQ_DOM), wallt, DateTimeRule::WALL_TIME);
- }
- if (modifiedRule == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
+ modifiedRule = new DateTimeRule(month, dom, dow, (dtype == DateTimeRule::DOW_GEQ_DOM), wallt, DateTimeRule::WALL_TIME);
}
+ if (modifiedRule == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
return modifiedRule;
}
@@ -962,24 +962,24 @@ VTZReader::read(void) {
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(VTimeZone)
VTimeZone::VTimeZone()
-: BasicTimeZone(), tz(nullptr), vtzlines(nullptr),
+: BasicTimeZone(), tz(nullptr), vtzlines(nullptr),
lastmod(MAX_MILLIS) {
}
VTimeZone::VTimeZone(const VTimeZone& source)
-: BasicTimeZone(source), tz(nullptr), vtzlines(nullptr),
+: BasicTimeZone(source), tz(nullptr), vtzlines(nullptr),
tzurl(source.tzurl), lastmod(source.lastmod),
olsonzid(source.olsonzid), icutzver(source.icutzver) {
- if (source.tz != nullptr) {
- tz = source.tz->clone();
+ if (source.tz != nullptr) {
+ tz = source.tz->clone();
}
- if (source.vtzlines != nullptr) {
+ if (source.vtzlines != nullptr) {
UErrorCode status = U_ZERO_ERROR;
int32_t size = source.vtzlines->size();
vtzlines = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, size, status);
- if (vtzlines == nullptr) {
- return;
- }
+ if (vtzlines == nullptr) {
+ return;
+ }
if (U_SUCCESS(status)) {
for (int32_t i = 0; i < size; i++) {
UnicodeString *line = (UnicodeString*)source.vtzlines->elementAt(i);
@@ -989,17 +989,17 @@ VTimeZone::VTimeZone(const VTimeZone& source)
}
}
}
- if (U_FAILURE(status) && vtzlines != nullptr) {
+ if (U_FAILURE(status) && vtzlines != nullptr) {
delete vtzlines;
}
}
}
VTimeZone::~VTimeZone() {
- if (tz != nullptr) {
+ if (tz != nullptr) {
delete tz;
}
- if (vtzlines != nullptr) {
+ if (vtzlines != nullptr) {
delete vtzlines;
}
}
@@ -1011,21 +1011,21 @@ VTimeZone::operator=(const VTimeZone& right) {
}
if (*this != right) {
BasicTimeZone::operator=(right);
- if (tz != nullptr) {
+ if (tz != nullptr) {
delete tz;
- tz = nullptr;
+ tz = nullptr;
}
- if (right.tz != nullptr) {
- tz = right.tz->clone();
+ if (right.tz != nullptr) {
+ tz = right.tz->clone();
}
- if (vtzlines != nullptr) {
+ if (vtzlines != nullptr) {
delete vtzlines;
}
- if (right.vtzlines != nullptr) {
+ if (right.vtzlines != nullptr) {
UErrorCode status = U_ZERO_ERROR;
int32_t size = right.vtzlines->size();
vtzlines = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, size, status);
- if (vtzlines != nullptr && U_SUCCESS(status)) {
+ if (vtzlines != nullptr && U_SUCCESS(status)) {
for (int32_t i = 0; i < size; i++) {
UnicodeString *line = (UnicodeString*)right.vtzlines->elementAt(i);
vtzlines->addElement(line->clone(), status);
@@ -1034,9 +1034,9 @@ VTimeZone::operator=(const VTimeZone& right) {
}
}
}
- if (U_FAILURE(status) && vtzlines != nullptr) {
+ if (U_FAILURE(status) && vtzlines != nullptr) {
delete vtzlines;
- vtzlines = nullptr;
+ vtzlines = nullptr;
}
}
tzurl = right.tzurl;
@@ -1076,18 +1076,18 @@ VTimeZone::operator!=(const TimeZone& that) const {
VTimeZone*
VTimeZone::createVTimeZoneByID(const UnicodeString& ID) {
VTimeZone *vtz = new VTimeZone();
- if (vtz == nullptr) {
- return nullptr;
- }
+ if (vtz == nullptr) {
+ return nullptr;
+ }
vtz->tz = (BasicTimeZone*)TimeZone::createTimeZone(ID);
vtz->tz->getID(vtz->olsonzid);
// Set ICU tzdata version
UErrorCode status = U_ZERO_ERROR;
- UResourceBundle *bundle = nullptr;
- const UChar* versionStr = nullptr;
+ UResourceBundle *bundle = nullptr;
+ const UChar* versionStr = nullptr;
int32_t len = 0;
- bundle = ures_openDirect(nullptr, "zoneinfo64", &status);
+ bundle = ures_openDirect(nullptr, "zoneinfo64", &status);
versionStr = ures_getStringByKey(bundle, "TZVersion", &len, &status);
if (U_SUCCESS(status)) {
vtz->icutzver.setTo(versionStr, len);
@@ -1099,26 +1099,26 @@ VTimeZone::createVTimeZoneByID(const UnicodeString& ID) {
VTimeZone*
VTimeZone::createVTimeZoneFromBasicTimeZone(const BasicTimeZone& basic_time_zone, UErrorCode &status) {
if (U_FAILURE(status)) {
- return nullptr;
+ return nullptr;
}
VTimeZone *vtz = new VTimeZone();
- if (vtz == nullptr) {
+ if (vtz == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
+ return nullptr;
}
- vtz->tz = basic_time_zone.clone();
- if (vtz->tz == nullptr) {
+ vtz->tz = basic_time_zone.clone();
+ if (vtz->tz == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
delete vtz;
- return nullptr;
+ return nullptr;
}
vtz->tz->getID(vtz->olsonzid);
// Set ICU tzdata version
- UResourceBundle *bundle = nullptr;
- const UChar* versionStr = nullptr;
+ UResourceBundle *bundle = nullptr;
+ const UChar* versionStr = nullptr;
int32_t len = 0;
- bundle = ures_openDirect(nullptr, "zoneinfo64", &status);
+ bundle = ures_openDirect(nullptr, "zoneinfo64", &status);
versionStr = ures_getStringByKey(bundle, "TZVersion", &len, &status);
if (U_SUCCESS(status)) {
vtz->icutzver.setTo(versionStr, len);
@@ -1130,18 +1130,18 @@ VTimeZone::createVTimeZoneFromBasicTimeZone(const BasicTimeZone& basic_time_zone
VTimeZone*
VTimeZone::createVTimeZone(const UnicodeString& vtzdata, UErrorCode& status) {
if (U_FAILURE(status)) {
- return nullptr;
+ return nullptr;
}
VTZReader reader(vtzdata);
VTimeZone *vtz = new VTimeZone();
- if (vtz == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
+ if (vtz == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
vtz->load(reader, status);
if (U_FAILURE(status)) {
delete vtz;
- return nullptr;
+ return nullptr;
}
return vtz;
}
@@ -1195,8 +1195,8 @@ VTimeZone::writeSimple(UDate time, UnicodeString& result, UErrorCode& status) co
writeSimple(time, writer, status);
}
-VTimeZone*
-VTimeZone::clone() const {
+VTimeZone*
+VTimeZone::clone() const {
return new VTimeZone(*this);
}
@@ -1269,9 +1269,9 @@ VTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial,
void
VTimeZone::load(VTZReader& reader, UErrorCode& status) {
vtzlines = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, DEFAULT_VTIMEZONE_LINES, status);
- if (vtzlines == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
+ if (vtzlines == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
if (U_FAILURE(status)) {
return;
}
@@ -1285,15 +1285,15 @@ VTimeZone::load(VTZReader& reader, UErrorCode& status) {
if (ch == 0xFFFF) {
// end of file
if (start && line.startsWith(ICAL_END_VTIMEZONE, -1)) {
- LocalPointer<UnicodeString> element(new UnicodeString(line), status);
- if (U_FAILURE(status)) {
- goto cleanupVtzlines;
- }
- vtzlines->addElement(element.getAlias(), status);
+ LocalPointer<UnicodeString> element(new UnicodeString(line), status);
if (U_FAILURE(status)) {
goto cleanupVtzlines;
}
- element.orphan(); // on success, vtzlines owns the object.
+ vtzlines->addElement(element.getAlias(), status);
+ if (U_FAILURE(status)) {
+ goto cleanupVtzlines;
+ }
+ element.orphan(); // on success, vtzlines owns the object.
success = TRUE;
}
break;
@@ -1307,15 +1307,15 @@ VTimeZone::load(VTZReader& reader, UErrorCode& status) {
// NOT followed by TAB/SP -> new line
if (start) {
if (line.length() > 0) {
- LocalPointer<UnicodeString> element(new UnicodeString(line), status);
+ LocalPointer<UnicodeString> element(new UnicodeString(line), status);
if (U_FAILURE(status)) {
goto cleanupVtzlines;
}
- vtzlines->addElement(element.getAlias(), status);
- if (U_FAILURE(status)) {
- goto cleanupVtzlines;
- }
- element.orphan(); // on success, vtzlines owns the object.
+ vtzlines->addElement(element.getAlias(), status);
+ if (U_FAILURE(status)) {
+ goto cleanupVtzlines;
+ }
+ element.orphan(); // on success, vtzlines owns the object.
}
}
line.remove();
@@ -1330,29 +1330,29 @@ VTimeZone::load(VTZReader& reader, UErrorCode& status) {
eol = TRUE;
if (start) {
if (line.startsWith(ICAL_END_VTIMEZONE, -1)) {
- LocalPointer<UnicodeString> element(new UnicodeString(line), status);
- if (U_FAILURE(status)) {
- goto cleanupVtzlines;
- }
- vtzlines->addElement(element.getAlias(), status);
+ LocalPointer<UnicodeString> element(new UnicodeString(line), status);
if (U_FAILURE(status)) {
goto cleanupVtzlines;
}
- element.orphan(); // on success, vtzlines owns the object.
+ vtzlines->addElement(element.getAlias(), status);
+ if (U_FAILURE(status)) {
+ goto cleanupVtzlines;
+ }
+ element.orphan(); // on success, vtzlines owns the object.
success = TRUE;
break;
}
} else {
if (line.startsWith(ICAL_BEGIN_VTIMEZONE, -1)) {
- LocalPointer<UnicodeString> element(new UnicodeString(line), status);
- if (U_FAILURE(status)) {
- goto cleanupVtzlines;
- }
- vtzlines->addElement(element.getAlias(), status);
+ LocalPointer<UnicodeString> element(new UnicodeString(line), status);
if (U_FAILURE(status)) {
goto cleanupVtzlines;
}
- element.orphan(); // on success, vtzlines owns the object.
+ vtzlines->addElement(element.getAlias(), status);
+ if (U_FAILURE(status)) {
+ goto cleanupVtzlines;
+ }
+ element.orphan(); // on success, vtzlines owns the object.
line.remove();
start = TRUE;
eol = FALSE;
@@ -1374,7 +1374,7 @@ VTimeZone::load(VTZReader& reader, UErrorCode& status) {
cleanupVtzlines:
delete vtzlines;
- vtzlines = nullptr;
+ vtzlines = nullptr;
}
// parser state
@@ -1390,12 +1390,12 @@ VTimeZone::parse(UErrorCode& status) {
if (U_FAILURE(status)) {
return;
}
- if (vtzlines == nullptr || vtzlines->size() == 0) {
+ if (vtzlines == nullptr || vtzlines->size() == 0) {
status = U_INVALID_STATE_ERROR;
return;
}
- InitialTimeZoneRule *initialRule = nullptr;
- RuleBasedTimeZone *rbtz = nullptr;
+ InitialTimeZoneRule *initialRule = nullptr;
+ RuleBasedTimeZone *rbtz = nullptr;
// timezone ID
UnicodeString tzid;
@@ -1414,16 +1414,16 @@ VTimeZone::parse(UErrorCode& status) {
UnicodeString name; // RFC2445 prop name
UnicodeString value; // RFC2445 prop value
- UVector *dates = nullptr; // list of RDATE or RRULE strings
- UVector *rules = nullptr; // list of TimeZoneRule instances
+ UVector *dates = nullptr; // list of RDATE or RRULE strings
+ UVector *rules = nullptr; // list of TimeZoneRule instances
int32_t finalRuleIdx = -1;
int32_t finalRuleCount = 0;
rules = new UVector(status);
- if (rules == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
+ if (rules == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
if (U_FAILURE(status)) {
goto cleanupParse;
}
@@ -1431,13 +1431,13 @@ VTimeZone::parse(UErrorCode& status) {
rules->setDeleter(deleteTimeZoneRule);
dates = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status);
- if (dates == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
+ if (dates == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
if (U_FAILURE(status)) {
goto cleanupParse;
}
-
+
for (n = 0; n < vtzlines->size(); n++) {
UnicodeString *line = (UnicodeString*)vtzlines->elementAt(n);
int32_t valueSep = line->indexOf(COLON);
@@ -1511,7 +1511,7 @@ VTimeZone::parse(UErrorCode& status) {
// by comma
UBool nextDate = TRUE;
int32_t dstart = 0;
- UnicodeString *dstr = nullptr;
+ UnicodeString *dstr = nullptr;
while (nextDate) {
int32_t dend = value.indexOf(COMMA, dstart);
if (dend == -1) {
@@ -1520,11 +1520,11 @@ VTimeZone::parse(UErrorCode& status) {
} else {
dstr = new UnicodeString(value, dstart, dend - dstart);
}
- if (dstr == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- } else {
- dates->addElement(dstr, status);
- }
+ if (dstr == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ dates->addElement(dstr, status);
+ }
if (U_FAILURE(status)) {
goto cleanupParse;
}
@@ -1536,15 +1536,15 @@ VTimeZone::parse(UErrorCode& status) {
goto cleanupParse;
}
isRRULE = true;
- LocalPointer<UnicodeString> element(new UnicodeString(value), status);
+ LocalPointer<UnicodeString> element(new UnicodeString(value), status);
if (U_FAILURE(status)) {
goto cleanupParse;
}
- dates->addElement(element.getAlias(), status);
- if (U_FAILURE(status)) {
- goto cleanupParse;
- }
- element.orphan(); // on success, dates owns the object.
+ dates->addElement(element.getAlias(), status);
+ if (U_FAILURE(status)) {
+ goto cleanupParse;
+ }
+ element.orphan(); // on success, dates owns the object.
} else if (name.compare(ICAL_END, -1) == 0) {
// Mandatory properties
if (dtstart.length() == 0 || from.length() == 0 || to.length() == 0) {
@@ -1556,7 +1556,7 @@ VTimeZone::parse(UErrorCode& status) {
}
// create a time zone rule
- TimeZoneRule *rule = nullptr;
+ TimeZoneRule *rule = nullptr;
int32_t fromOffset = 0;
int32_t toOffset = 0;
int32_t rawOffset = 0;
@@ -1598,7 +1598,7 @@ VTimeZone::parse(UErrorCode& status) {
} else {
rule = createRuleByRDATE(zonename, rawOffset, dstSavings, start, dates, fromOffset, status);
}
- if (U_FAILURE(status) || rule == nullptr) {
+ if (U_FAILURE(status) || rule == nullptr) {
goto cleanupParse;
} else {
UBool startAvail = rule->getFirstStart(fromOffset, 0, actualStart);
@@ -1638,24 +1638,24 @@ VTimeZone::parse(UErrorCode& status) {
// Create a initial rule
getDefaultTZName(tzid, FALSE, zonename);
- initialRule = new InitialTimeZoneRule(zonename, initialRawOffset, initialDSTSavings);
- if (initialRule == nullptr) {
+ initialRule = new InitialTimeZoneRule(zonename, initialRawOffset, initialDSTSavings);
+ if (initialRule == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
goto cleanupParse;
}
// Finally, create the RuleBasedTimeZone
rbtz = new RuleBasedTimeZone(tzid, initialRule);
- if (rbtz == nullptr) {
+ if (rbtz == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
goto cleanupParse;
}
- initialRule = nullptr; // already adopted by RBTZ, no need to delete
+ initialRule = nullptr; // already adopted by RBTZ, no need to delete
for (n = 0; n < rules->size(); n++) {
TimeZoneRule *r = (TimeZoneRule*)rules->elementAt(n);
AnnualTimeZoneRule *atzrule = dynamic_cast<AnnualTimeZoneRule *>(r);
- if (atzrule != nullptr) {
+ if (atzrule != nullptr) {
if (atzrule->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) {
finalRuleCount++;
finalRuleIdx = n;
@@ -1700,7 +1700,7 @@ VTimeZone::parse(UErrorCode& status) {
}
}
- TimeZoneRule *newRule = nullptr;
+ TimeZoneRule *newRule = nullptr;
UnicodeString tznam;
if (start == finalStart) {
// Transform this into a single transition
@@ -1723,7 +1723,7 @@ VTimeZone::parse(UErrorCode& status) {
finalRule->getStartYear(),
y);
}
- if (newRule == nullptr) {
+ if (newRule == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
goto cleanupParse;
}
@@ -1755,20 +1755,20 @@ VTimeZone::parse(UErrorCode& status) {
return;
cleanupParse:
- if (rules != nullptr) {
+ if (rules != nullptr) {
while (!rules->isEmpty()) {
TimeZoneRule *r = (TimeZoneRule*)rules->orphanElementAt(0);
delete r;
}
delete rules;
}
- if (dates != nullptr) {
+ if (dates != nullptr) {
delete dates;
}
- if (initialRule != nullptr) {
+ if (initialRule != nullptr) {
delete initialRule;
}
- if (rbtz != nullptr) {
+ if (rbtz != nullptr) {
delete rbtz;
}
return;
@@ -1776,7 +1776,7 @@ cleanupParse:
void
VTimeZone::write(VTZWriter& writer, UErrorCode& status) const {
- if (vtzlines != nullptr) {
+ if (vtzlines != nullptr) {
for (int32_t i = 0; i < vtzlines->size(); i++) {
UnicodeString *line = (UnicodeString*)vtzlines->elementAt(i);
if (line->startsWith(ICAL_TZURL, -1)
@@ -1798,16 +1798,16 @@ VTimeZone::write(VTZWriter& writer, UErrorCode& status) const {
}
}
} else {
- UnicodeString icutzprop;
- UVector customProps(nullptr, uhash_compareUnicodeString, status);
+ UnicodeString icutzprop;
+ UVector customProps(nullptr, uhash_compareUnicodeString, status);
if (olsonzid.length() > 0 && icutzver.length() > 0) {
- icutzprop.append(olsonzid);
- icutzprop.append(u'[');
- icutzprop.append(icutzver);
- icutzprop.append(u']');
- customProps.addElement(&icutzprop, status);
+ icutzprop.append(olsonzid);
+ icutzprop.append(u'[');
+ icutzprop.append(icutzver);
+ icutzprop.append(u']');
+ customProps.addElement(&icutzprop, status);
}
- writeZone(writer, *tz, &customProps, status);
+ writeZone(writer, *tz, &customProps, status);
}
}
@@ -1816,8 +1816,8 @@ VTimeZone::write(UDate start, VTZWriter& writer, UErrorCode& status) const {
if (U_FAILURE(status)) {
return;
}
- InitialTimeZoneRule *initial = nullptr;
- UVector *transitionRules = nullptr;
+ InitialTimeZoneRule *initial = nullptr;
+ UVector *transitionRules = nullptr;
UVector customProps(uprv_deleteUObject, uhash_compareUnicodeString, status);
UnicodeString tzid;
@@ -1830,7 +1830,7 @@ VTimeZone::write(UDate start, VTZWriter& writer, UErrorCode& status) const {
// Create a RuleBasedTimeZone with the subset rule
getID(tzid);
RuleBasedTimeZone rbtz(tzid, initial);
- if (transitionRules != nullptr) {
+ if (transitionRules != nullptr) {
while (!transitionRules->isEmpty()) {
TimeZoneRule *tr = (TimeZoneRule*)transitionRules->orphanElementAt(0);
rbtz.addTransitionRule(tr, status);
@@ -1839,7 +1839,7 @@ VTimeZone::write(UDate start, VTZWriter& writer, UErrorCode& status) const {
}
}
delete transitionRules;
- transitionRules = nullptr;
+ transitionRules = nullptr;
}
rbtz.complete(status);
if (U_FAILURE(status)) {
@@ -1848,10 +1848,10 @@ VTimeZone::write(UDate start, VTZWriter& writer, UErrorCode& status) const {
if (olsonzid.length() > 0 && icutzver.length() > 0) {
UnicodeString *icutzprop = new UnicodeString(ICU_TZINFO_PROP);
- if (icutzprop == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- goto cleanupWritePartial;
- }
+ if (icutzprop == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanupWritePartial;
+ }
icutzprop->append(olsonzid);
icutzprop->append((UChar)0x005B/*'['*/);
icutzprop->append(icutzver);
@@ -1868,10 +1868,10 @@ VTimeZone::write(UDate start, VTZWriter& writer, UErrorCode& status) const {
return;
cleanupWritePartial:
- if (initial != nullptr) {
+ if (initial != nullptr) {
delete initial;
}
- if (transitionRules != nullptr) {
+ if (transitionRules != nullptr) {
while (!transitionRules->isEmpty()) {
TimeZoneRule *tr = (TimeZoneRule*)transitionRules->orphanElementAt(0);
delete tr;
@@ -1890,14 +1890,14 @@ VTimeZone::writeSimple(UDate time, VTZWriter& writer, UErrorCode& status) const
UnicodeString tzid;
// Extract simple rules
- InitialTimeZoneRule *initial = nullptr;
- AnnualTimeZoneRule *std = nullptr, *dst = nullptr;
+ InitialTimeZoneRule *initial = nullptr;
+ AnnualTimeZoneRule *std = nullptr, *dst = nullptr;
getSimpleRulesNear(time, initial, std, dst, status);
if (U_SUCCESS(status)) {
// Create a RuleBasedTimeZone with the subset rule
getID(tzid);
RuleBasedTimeZone rbtz(tzid, initial);
- if (std != nullptr && dst != nullptr) {
+ if (std != nullptr && dst != nullptr) {
rbtz.addTransitionRule(std, status);
rbtz.addTransitionRule(dst, status);
}
@@ -1907,10 +1907,10 @@ VTimeZone::writeSimple(UDate time, VTZWriter& writer, UErrorCode& status) const
if (olsonzid.length() > 0 && icutzver.length() > 0) {
UnicodeString *icutzprop = new UnicodeString(ICU_TZINFO_PROP);
- if (icutzprop == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- goto cleanupWriteSimple;
- }
+ if (icutzprop == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanupWriteSimple;
+ }
icutzprop->append(olsonzid);
icutzprop->append((UChar)0x005B/*'['*/);
icutzprop->append(icutzver);
@@ -1928,13 +1928,13 @@ VTimeZone::writeSimple(UDate time, VTZWriter& writer, UErrorCode& status) const
return;
cleanupWriteSimple:
- if (initial != nullptr) {
+ if (initial != nullptr) {
delete initial;
}
- if (std != nullptr) {
+ if (std != nullptr) {
delete std;
}
- if (dst != nullptr) {
+ if (dst != nullptr) {
delete dst;
}
}
@@ -1950,7 +1950,7 @@ VTimeZone::writeZone(VTZWriter& w, BasicTimeZone& basictz,
return;
}
- if (customProps != nullptr) {
+ if (customProps != nullptr) {
for (int32_t i = 0; i < customProps->size(); i++) {
UnicodeString *custprop = (UnicodeString*)customProps->elementAt(i);
w.write(*custprop);
@@ -1971,7 +1971,7 @@ VTimeZone::writeZone(VTZWriter& w, BasicTimeZone& basictz,
UDate dstStartTime = 0.0;
UDate dstUntilTime = 0.0;
int32_t dstCount = 0;
- AnnualTimeZoneRule *finalDstRule = nullptr;
+ AnnualTimeZoneRule *finalDstRule = nullptr;
UnicodeString stdName;
int32_t stdFromOffset = 0;
@@ -1985,7 +1985,7 @@ VTimeZone::writeZone(VTZWriter& w, BasicTimeZone& basictz,
UDate stdStartTime = 0.0;
UDate stdUntilTime = 0.0;
int32_t stdCount = 0;
- AnnualTimeZoneRule *finalStdRule = nullptr;
+ AnnualTimeZoneRule *finalStdRule = nullptr;
int32_t year, month, dom, dow, doy, mid;
UBool hasTransitions = FALSE;
@@ -2012,11 +2012,11 @@ VTimeZone::writeZone(VTZWriter& w, BasicTimeZone& basictz,
UBool sameRule = FALSE;
const AnnualTimeZoneRule *atzrule;
if (isDst) {
- if (finalDstRule == nullptr
- && (atzrule = dynamic_cast<const AnnualTimeZoneRule *>(tzt.getTo())) != nullptr
+ if (finalDstRule == nullptr
+ && (atzrule = dynamic_cast<const AnnualTimeZoneRule *>(tzt.getTo())) != nullptr
&& atzrule->getEndYear() == AnnualTimeZoneRule::MAX_YEAR
) {
- finalDstRule = atzrule->clone();
+ finalDstRule = atzrule->clone();
}
if (dstCount > 0) {
if (year == dstStartYear + dstCount
@@ -2059,15 +2059,15 @@ VTimeZone::writeZone(VTZWriter& w, BasicTimeZone& basictz,
dstStartTime = dstUntilTime = t;
dstCount = 1;
}
- if (finalStdRule != nullptr && finalDstRule != nullptr) {
+ if (finalStdRule != nullptr && finalDstRule != nullptr) {
break;
}
} else {
- if (finalStdRule == nullptr
- && (atzrule = dynamic_cast<const AnnualTimeZoneRule *>(tzt.getTo())) != nullptr
+ if (finalStdRule == nullptr
+ && (atzrule = dynamic_cast<const AnnualTimeZoneRule *>(tzt.getTo())) != nullptr
&& atzrule->getEndYear() == AnnualTimeZoneRule::MAX_YEAR
) {
- finalStdRule = atzrule->clone();
+ finalStdRule = atzrule->clone();
}
if (stdCount > 0) {
if (year == stdStartYear + stdCount
@@ -2110,7 +2110,7 @@ VTimeZone::writeZone(VTZWriter& w, BasicTimeZone& basictz,
stdStartTime = stdUntilTime = t;
stdCount = 1;
}
- if (finalStdRule != nullptr && finalDstRule != nullptr) {
+ if (finalStdRule != nullptr && finalDstRule != nullptr) {
break;
}
}
@@ -2134,7 +2134,7 @@ VTimeZone::writeZone(VTZWriter& w, BasicTimeZone& basictz,
}
} else {
if (dstCount > 0) {
- if (finalDstRule == nullptr) {
+ if (finalDstRule == nullptr) {
if (dstCount == 1) {
writeZonePropsByTime(w, TRUE, dstName, dstFromOffset, dstToOffset, dstStartTime,
TRUE, status);
@@ -2176,7 +2176,7 @@ VTimeZone::writeZone(VTZWriter& w, BasicTimeZone& basictz,
}
}
if (stdCount > 0) {
- if (finalStdRule == nullptr) {
+ if (finalStdRule == nullptr) {
if (stdCount == 1) {
writeZonePropsByTime(w, FALSE, stdName, stdFromOffset, stdToOffset, stdStartTime,
TRUE, status);
@@ -2222,10 +2222,10 @@ VTimeZone::writeZone(VTZWriter& w, BasicTimeZone& basictz,
cleanupWriteZone:
- if (finalStdRule != nullptr) {
+ if (finalStdRule != nullptr) {
delete finalStdRule;
}
- if (finalDstRule != nullptr) {
+ if (finalDstRule != nullptr) {
delete finalDstRule;
}
}
@@ -2538,11 +2538,11 @@ VTimeZone::writeFinalRule(VTZWriter& writer, UBool isDst, const AnnualTimeZoneRu
return;
}
UBool modifiedRule = TRUE;
- const DateTimeRule *dtrule = toWallTimeRule(rule->getRule(), fromRawOffset, fromDSTSavings, status);
- if (U_FAILURE(status)) {
- return;
- }
- if (dtrule == nullptr) {
+ const DateTimeRule *dtrule = toWallTimeRule(rule->getRule(), fromRawOffset, fromDSTSavings, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (dtrule == nullptr) {
modifiedRule = FALSE;
dtrule = rule->getRule();
}
diff --git a/contrib/libs/icu/i18n/vzone.cpp b/contrib/libs/icu/i18n/vzone.cpp
index 7e3a5544fd..0405cb13ea 100644
--- a/contrib/libs/icu/i18n/vzone.cpp
+++ b/contrib/libs/icu/i18n/vzone.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/vzone.h b/contrib/libs/icu/i18n/vzone.h
index 17df92e17b..9e3e0b05a9 100644
--- a/contrib/libs/icu/i18n/vzone.h
+++ b/contrib/libs/icu/i18n/vzone.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/windtfmt.cpp b/contrib/libs/icu/i18n/windtfmt.cpp
index bcf272bc61..02518d17b3 100644
--- a/contrib/libs/icu/i18n/windtfmt.cpp
+++ b/contrib/libs/icu/i18n/windtfmt.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
********************************************************************************
@@ -13,7 +13,7 @@
#include "unicode/utypes.h"
-#if U_PLATFORM_USES_ONLY_WIN32_API
+#if U_PLATFORM_USES_ONLY_WIN32_API
#if !UCONFIG_NO_FORMATTING
@@ -35,9 +35,9 @@
#include "windtfmt.h"
#include "wintzimpl.h"
-#ifndef WIN32_LEAN_AND_MEAN
+#ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
-#endif
+#endif
# define VC_EXTRALEAN
# define NOUSER
# define NOSERVICE
@@ -94,83 +94,83 @@ UnicodeString* Win32DateFormat::getTimeDateFormat(const Calendar *cal, const Loc
return result;
}
-// TODO: This is copied in both winnmfmt.cpp and windtfmt.cpp, but really should
-// be factored out into a common helper for both.
-static UErrorCode GetEquivalentWindowsLocaleName(const Locale& locale, UnicodeString** buffer)
-{
- UErrorCode status = U_ZERO_ERROR;
- char asciiBCP47Tag[LOCALE_NAME_MAX_LENGTH] = {};
-
- // Convert from names like "en_CA" and "de_DE@collation=phonebook" to "en-CA" and "de-DE-u-co-phonebk".
- (void)uloc_toLanguageTag(locale.getName(), asciiBCP47Tag, UPRV_LENGTHOF(asciiBCP47Tag), FALSE, &status);
-
- if (U_SUCCESS(status))
- {
- // Need it to be UTF-16, not 8-bit
- // TODO: This seems like a good thing for a helper
- wchar_t bcp47Tag[LOCALE_NAME_MAX_LENGTH] = {};
- int32_t i;
- for (i = 0; i < UPRV_LENGTHOF(bcp47Tag); i++)
- {
- if (asciiBCP47Tag[i] == '\0')
- {
- break;
- }
- else
- {
- // normally just copy the character
- bcp47Tag[i] = static_cast<wchar_t>(asciiBCP47Tag[i]);
- }
- }
-
- // Ensure it's null terminated
- if (i < (UPRV_LENGTHOF(bcp47Tag) - 1))
- {
- bcp47Tag[i] = L'\0';
- }
- else
- {
- // Ran out of room.
- bcp47Tag[UPRV_LENGTHOF(bcp47Tag) - 1] = L'\0';
- }
-
-
- wchar_t windowsLocaleName[LOCALE_NAME_MAX_LENGTH] = {};
-
- // Note: On Windows versions below 10, there is no support for locale name aliases.
- // This means that it will fail for locales where ICU has a completely different
- // name (like ku vs ckb), and it will also not work for alternate sort locale
- // names like "de-DE-u-co-phonebk".
-
- // TODO: We could add some sort of exception table for cases like ku vs ckb.
-
- int length = ResolveLocaleName(bcp47Tag, windowsLocaleName, UPRV_LENGTHOF(windowsLocaleName));
-
- if (length > 0)
- {
- *buffer = new UnicodeString(windowsLocaleName);
- }
- else
- {
- status = U_UNSUPPORTED_ERROR;
- }
- }
- return status;
-}
-
+// TODO: This is copied in both winnmfmt.cpp and windtfmt.cpp, but really should
+// be factored out into a common helper for both.
+static UErrorCode GetEquivalentWindowsLocaleName(const Locale& locale, UnicodeString** buffer)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ char asciiBCP47Tag[LOCALE_NAME_MAX_LENGTH] = {};
+
+ // Convert from names like "en_CA" and "de_DE@collation=phonebook" to "en-CA" and "de-DE-u-co-phonebk".
+ (void)uloc_toLanguageTag(locale.getName(), asciiBCP47Tag, UPRV_LENGTHOF(asciiBCP47Tag), FALSE, &status);
+
+ if (U_SUCCESS(status))
+ {
+ // Need it to be UTF-16, not 8-bit
+ // TODO: This seems like a good thing for a helper
+ wchar_t bcp47Tag[LOCALE_NAME_MAX_LENGTH] = {};
+ int32_t i;
+ for (i = 0; i < UPRV_LENGTHOF(bcp47Tag); i++)
+ {
+ if (asciiBCP47Tag[i] == '\0')
+ {
+ break;
+ }
+ else
+ {
+ // normally just copy the character
+ bcp47Tag[i] = static_cast<wchar_t>(asciiBCP47Tag[i]);
+ }
+ }
+
+ // Ensure it's null terminated
+ if (i < (UPRV_LENGTHOF(bcp47Tag) - 1))
+ {
+ bcp47Tag[i] = L'\0';
+ }
+ else
+ {
+ // Ran out of room.
+ bcp47Tag[UPRV_LENGTHOF(bcp47Tag) - 1] = L'\0';
+ }
+
+
+ wchar_t windowsLocaleName[LOCALE_NAME_MAX_LENGTH] = {};
+
+ // Note: On Windows versions below 10, there is no support for locale name aliases.
+ // This means that it will fail for locales where ICU has a completely different
+ // name (like ku vs ckb), and it will also not work for alternate sort locale
+ // names like "de-DE-u-co-phonebk".
+
+ // TODO: We could add some sort of exception table for cases like ku vs ckb.
+
+ int length = ResolveLocaleName(bcp47Tag, windowsLocaleName, UPRV_LENGTHOF(windowsLocaleName));
+
+ if (length > 0)
+ {
+ *buffer = new UnicodeString(windowsLocaleName);
+ }
+ else
+ {
+ status = U_UNSUPPORTED_ERROR;
+ }
+ }
+ return status;
+}
+
// TODO: Range-check timeStyle, dateStyle
Win32DateFormat::Win32DateFormat(DateFormat::EStyle timeStyle, DateFormat::EStyle dateStyle, const Locale &locale, UErrorCode &status)
- : DateFormat(), fDateTimeMsg(NULL), fTimeStyle(timeStyle), fDateStyle(dateStyle), fLocale(locale), fZoneID(), fWindowsLocaleName(nullptr)
+ : DateFormat(), fDateTimeMsg(NULL), fTimeStyle(timeStyle), fDateStyle(dateStyle), fLocale(locale), fZoneID(), fWindowsLocaleName(nullptr)
{
if (U_SUCCESS(status)) {
- GetEquivalentWindowsLocaleName(locale, &fWindowsLocaleName);
- // Note: In the previous code, it would look up the LCID for the locale, and if
- // the locale was not recognized then it would get an LCID of 0, which is a
- // synonym for LOCALE_USER_DEFAULT on Windows.
- // If the above method fails, then fWindowsLocaleName will remain as nullptr, and
- // then we will pass nullptr to API GetLocaleInfoEx, which is the same as passing
- // LOCALE_USER_DEFAULT.
-
+ GetEquivalentWindowsLocaleName(locale, &fWindowsLocaleName);
+ // Note: In the previous code, it would look up the LCID for the locale, and if
+ // the locale was not recognized then it would get an LCID of 0, which is a
+ // synonym for LOCALE_USER_DEFAULT on Windows.
+ // If the above method fails, then fWindowsLocaleName will remain as nullptr, and
+ // then we will pass nullptr to API GetLocaleInfoEx, which is the same as passing
+ // LOCALE_USER_DEFAULT.
+
fTZI = NEW_ARRAY(TIME_ZONE_INFORMATION, 1);
uprv_memset(fTZI, 0, sizeof(TIME_ZONE_INFORMATION));
adoptCalendar(Calendar::createInstance(locale, status));
@@ -188,7 +188,7 @@ Win32DateFormat::~Win32DateFormat()
// delete fCalendar;
uprv_free(fTZI);
delete fDateTimeMsg;
- delete fWindowsLocaleName;
+ delete fWindowsLocaleName;
}
Win32DateFormat &Win32DateFormat::operator=(const Win32DateFormat &other)
@@ -208,18 +208,18 @@ Win32DateFormat &Win32DateFormat::operator=(const Win32DateFormat &other)
this->fTZI = NEW_ARRAY(TIME_ZONE_INFORMATION, 1);
*this->fTZI = *other.fTZI;
- this->fWindowsLocaleName = other.fWindowsLocaleName == NULL ? NULL : new UnicodeString(*other.fWindowsLocaleName);
-
+ this->fWindowsLocaleName = other.fWindowsLocaleName == NULL ? NULL : new UnicodeString(*other.fWindowsLocaleName);
+
return *this;
}
-Win32DateFormat *Win32DateFormat::clone() const
+Win32DateFormat *Win32DateFormat::clone() const
{
return new Win32DateFormat(*this);
}
// TODO: Is just ignoring pos the right thing?
-UnicodeString &Win32DateFormat::format(Calendar &cal, UnicodeString &appendTo, FieldPosition & /* pos */) const
+UnicodeString &Win32DateFormat::format(Calendar &cal, UnicodeString &appendTo, FieldPosition & /* pos */) const
{
FILETIME ft;
SYSTEMTIME st_gmt;
@@ -263,7 +263,7 @@ UnicodeString &Win32DateFormat::format(Calendar &cal, UnicodeString &appendTo, F
return appendTo;
}
-void Win32DateFormat::parse(const UnicodeString& /* text */, Calendar& /* cal */, ParsePosition& pos) const
+void Win32DateFormat::parse(const UnicodeString& /* text */, Calendar& /* cal */, ParsePosition& pos) const
{
pos.setErrorIndex(pos.getIndex());
}
@@ -306,25 +306,25 @@ static const DWORD dfFlags[] = {DATE_LONGDATE, DATE_LONGDATE, DATE_SHORTDATE, DA
void Win32DateFormat::formatDate(const SYSTEMTIME *st, UnicodeString &appendTo) const
{
- int result=0;
+ int result=0;
wchar_t stackBuffer[STACK_BUFFER_SIZE];
wchar_t *buffer = stackBuffer;
- const wchar_t *localeName = nullptr;
+ const wchar_t *localeName = nullptr;
- if (fWindowsLocaleName != nullptr)
- {
- localeName = reinterpret_cast<const wchar_t*>(toOldUCharPtr(fWindowsLocaleName->getTerminatedBuffer()));
- }
-
- result = GetDateFormatEx(localeName, dfFlags[fDateStyle - kDateOffset], st, NULL, buffer, STACK_BUFFER_SIZE, NULL);
+ if (fWindowsLocaleName != nullptr)
+ {
+ localeName = reinterpret_cast<const wchar_t*>(toOldUCharPtr(fWindowsLocaleName->getTerminatedBuffer()));
+ }
+ result = GetDateFormatEx(localeName, dfFlags[fDateStyle - kDateOffset], st, NULL, buffer, STACK_BUFFER_SIZE, NULL);
+
if (result == 0) {
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
- int newLength = GetDateFormatEx(localeName, dfFlags[fDateStyle - kDateOffset], st, NULL, NULL, 0, NULL);
+ int newLength = GetDateFormatEx(localeName, dfFlags[fDateStyle - kDateOffset], st, NULL, NULL, 0, NULL);
buffer = NEW_ARRAY(wchar_t, newLength);
-
- GetDateFormatEx(localeName, dfFlags[fDateStyle - kDateOffset], st, NULL, buffer, newLength, NULL);
+
+ GetDateFormatEx(localeName, dfFlags[fDateStyle - kDateOffset], st, NULL, buffer, newLength, NULL);
}
}
@@ -342,22 +342,22 @@ void Win32DateFormat::formatTime(const SYSTEMTIME *st, UnicodeString &appendTo)
int result;
wchar_t stackBuffer[STACK_BUFFER_SIZE];
wchar_t *buffer = stackBuffer;
- const wchar_t *localeName = nullptr;
+ const wchar_t *localeName = nullptr;
- if (fWindowsLocaleName != nullptr)
- {
- localeName = reinterpret_cast<const wchar_t*>(toOldUCharPtr(fWindowsLocaleName->getTerminatedBuffer()));
- }
-
- result = GetTimeFormatEx(localeName, tfFlags[fTimeStyle], st, NULL, buffer, STACK_BUFFER_SIZE);
+ if (fWindowsLocaleName != nullptr)
+ {
+ localeName = reinterpret_cast<const wchar_t*>(toOldUCharPtr(fWindowsLocaleName->getTerminatedBuffer()));
+ }
+ result = GetTimeFormatEx(localeName, tfFlags[fTimeStyle], st, NULL, buffer, STACK_BUFFER_SIZE);
+
if (result == 0) {
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
- int newLength = GetTimeFormatEx(localeName, tfFlags[fTimeStyle], st, NULL, NULL, 0);
+ int newLength = GetTimeFormatEx(localeName, tfFlags[fTimeStyle], st, NULL, NULL, 0);
buffer = NEW_ARRAY(wchar_t, newLength);
-
- GetTimeFormatEx(localeName, tfFlags[fTimeStyle], st, NULL, buffer, newLength);
+
+ GetTimeFormatEx(localeName, tfFlags[fTimeStyle], st, NULL, buffer, newLength);
}
}
@@ -385,8 +385,8 @@ UnicodeString Win32DateFormat::setTimeZoneInfo(TIME_ZONE_INFORMATION *tzi, const
for (int z = 0; z < ec; z += 1) {
UnicodeString equiv = TimeZone::getEquivalentID(icuid, z);
- found = uprv_getWindowsTimeZoneInfo(tzi, equiv.getBuffer(), equiv.length());
- if (found) {
+ found = uprv_getWindowsTimeZoneInfo(tzi, equiv.getBuffer(), equiv.length());
+ if (found) {
break;
}
}
@@ -404,5 +404,5 @@ U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */
-#endif // U_PLATFORM_USES_ONLY_WIN32_API
+#endif // U_PLATFORM_USES_ONLY_WIN32_API
diff --git a/contrib/libs/icu/i18n/windtfmt.h b/contrib/libs/icu/i18n/windtfmt.h
index 7fe7f68f45..3b59a018ce 100644
--- a/contrib/libs/icu/i18n/windtfmt.h
+++ b/contrib/libs/icu/i18n/windtfmt.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
********************************************************************************
@@ -16,7 +16,7 @@
#include "unicode/utypes.h"
-#if U_PLATFORM_USES_ONLY_WIN32_API
+#if U_PLATFORM_USES_ONLY_WIN32_API
#if !UCONFIG_NO_FORMATTING
@@ -48,7 +48,7 @@ public:
virtual ~Win32DateFormat();
- virtual Win32DateFormat *clone() const;
+ virtual Win32DateFormat *clone() const;
Win32DateFormat &operator=(const Win32DateFormat &other);
@@ -95,7 +95,7 @@ public:
* <pre>
* . Base* polymorphic_pointer = createPolymorphicObject();
* . if (polymorphic_pointer->getDynamicClassID() ==
- * . derived::getStaticClassID()) ...
+ * . derived::getStaticClassID()) ...
* </pre>
* @return The class ID for all objects of this class.
*/
@@ -126,14 +126,14 @@ private:
Locale fLocale;
UnicodeString fZoneID;
TIME_ZONE_INFORMATION *fTZI;
-
- UnicodeString* fWindowsLocaleName; // Stores the equivalent Windows locale name.
+
+ UnicodeString* fWindowsLocaleName; // Stores the equivalent Windows locale name.
};
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */
-#endif // U_PLATFORM_USES_ONLY_WIN32_API
+#endif // U_PLATFORM_USES_ONLY_WIN32_API
#endif // __WINDTFMT
diff --git a/contrib/libs/icu/i18n/winnmfmt.cpp b/contrib/libs/icu/i18n/winnmfmt.cpp
index 72da1be28b..1c5e969ae6 100644
--- a/contrib/libs/icu/i18n/winnmfmt.cpp
+++ b/contrib/libs/icu/i18n/winnmfmt.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
********************************************************************************
@@ -28,9 +28,9 @@
#include "uassert.h"
#include "locmap.h"
-#ifndef WIN32_LEAN_AND_MEAN
+#ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
-#endif
+#endif
# define VC_EXTRALEAN
# define NOUSER
# define NOSERVICE
@@ -60,43 +60,43 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Win32NumberFormat)
* end in ";0" then the return value should be multiplied by 10.
* (e.g. "3" => 30, "3;2" => 320)
*/
-static UINT getGrouping(const wchar_t *grouping)
+static UINT getGrouping(const wchar_t *grouping)
{
UINT g = 0;
- const wchar_t *s;
+ const wchar_t *s;
- for (s = grouping; *s != L'\0'; s += 1) {
- if (*s > L'0' && *s < L'9') {
- g = g * 10 + (*s - L'0');
- } else if (*s != L';') {
+ for (s = grouping; *s != L'\0'; s += 1) {
+ if (*s > L'0' && *s < L'9') {
+ g = g * 10 + (*s - L'0');
+ } else if (*s != L';') {
break;
}
}
- if (*s != L'0') {
+ if (*s != L'0') {
g *= 10;
}
return g;
}
-static void getNumberFormat(NUMBERFMTW *fmt, const wchar_t *windowsLocaleName)
+static void getNumberFormat(NUMBERFMTW *fmt, const wchar_t *windowsLocaleName)
{
- wchar_t buf[10];
+ wchar_t buf[10];
- GetLocaleInfoEx(windowsLocaleName, LOCALE_RETURN_NUMBER|LOCALE_IDIGITS, (LPWSTR) &fmt->NumDigits, sizeof(UINT));
- GetLocaleInfoEx(windowsLocaleName, LOCALE_RETURN_NUMBER|LOCALE_ILZERO, (LPWSTR) &fmt->LeadingZero, sizeof(UINT));
+ GetLocaleInfoEx(windowsLocaleName, LOCALE_RETURN_NUMBER|LOCALE_IDIGITS, (LPWSTR) &fmt->NumDigits, sizeof(UINT));
+ GetLocaleInfoEx(windowsLocaleName, LOCALE_RETURN_NUMBER|LOCALE_ILZERO, (LPWSTR) &fmt->LeadingZero, sizeof(UINT));
- GetLocaleInfoEx(windowsLocaleName, LOCALE_SGROUPING, (LPWSTR)buf, 10);
+ GetLocaleInfoEx(windowsLocaleName, LOCALE_SGROUPING, (LPWSTR)buf, 10);
fmt->Grouping = getGrouping(buf);
fmt->lpDecimalSep = NEW_ARRAY(wchar_t, 6);
- GetLocaleInfoEx(windowsLocaleName, LOCALE_SDECIMAL, fmt->lpDecimalSep, 6);
+ GetLocaleInfoEx(windowsLocaleName, LOCALE_SDECIMAL, fmt->lpDecimalSep, 6);
fmt->lpThousandSep = NEW_ARRAY(wchar_t, 6);
- GetLocaleInfoEx(windowsLocaleName, LOCALE_STHOUSAND, fmt->lpThousandSep, 6);
+ GetLocaleInfoEx(windowsLocaleName, LOCALE_STHOUSAND, fmt->lpThousandSep, 6);
- GetLocaleInfoEx(windowsLocaleName, LOCALE_RETURN_NUMBER|LOCALE_INEGNUMBER, (LPWSTR) &fmt->NegativeOrder, sizeof(UINT));
+ GetLocaleInfoEx(windowsLocaleName, LOCALE_RETURN_NUMBER|LOCALE_INEGNUMBER, (LPWSTR) &fmt->NegativeOrder, sizeof(UINT));
}
static void freeNumberFormat(NUMBERFMTW *fmt)
@@ -107,27 +107,27 @@ static void freeNumberFormat(NUMBERFMTW *fmt)
}
}
-static void getCurrencyFormat(CURRENCYFMTW *fmt, const wchar_t *windowsLocaleName)
+static void getCurrencyFormat(CURRENCYFMTW *fmt, const wchar_t *windowsLocaleName)
{
- wchar_t buf[10];
+ wchar_t buf[10];
- GetLocaleInfoEx(windowsLocaleName, LOCALE_RETURN_NUMBER|LOCALE_ICURRDIGITS, (LPWSTR) &fmt->NumDigits, sizeof(UINT));
- GetLocaleInfoEx(windowsLocaleName, LOCALE_RETURN_NUMBER|LOCALE_ILZERO, (LPWSTR) &fmt->LeadingZero, sizeof(UINT));
+ GetLocaleInfoEx(windowsLocaleName, LOCALE_RETURN_NUMBER|LOCALE_ICURRDIGITS, (LPWSTR) &fmt->NumDigits, sizeof(UINT));
+ GetLocaleInfoEx(windowsLocaleName, LOCALE_RETURN_NUMBER|LOCALE_ILZERO, (LPWSTR) &fmt->LeadingZero, sizeof(UINT));
- GetLocaleInfoEx(windowsLocaleName, LOCALE_SMONGROUPING, (LPWSTR)buf, sizeof(buf));
+ GetLocaleInfoEx(windowsLocaleName, LOCALE_SMONGROUPING, (LPWSTR)buf, sizeof(buf));
fmt->Grouping = getGrouping(buf);
fmt->lpDecimalSep = NEW_ARRAY(wchar_t, 6);
- GetLocaleInfoEx(windowsLocaleName, LOCALE_SMONDECIMALSEP, fmt->lpDecimalSep, 6);
+ GetLocaleInfoEx(windowsLocaleName, LOCALE_SMONDECIMALSEP, fmt->lpDecimalSep, 6);
fmt->lpThousandSep = NEW_ARRAY(wchar_t, 6);
- GetLocaleInfoEx(windowsLocaleName, LOCALE_SMONTHOUSANDSEP, fmt->lpThousandSep, 6);
+ GetLocaleInfoEx(windowsLocaleName, LOCALE_SMONTHOUSANDSEP, fmt->lpThousandSep, 6);
- GetLocaleInfoEx(windowsLocaleName, LOCALE_RETURN_NUMBER|LOCALE_INEGCURR, (LPWSTR) &fmt->NegativeOrder, sizeof(UINT));
- GetLocaleInfoEx(windowsLocaleName, LOCALE_RETURN_NUMBER|LOCALE_ICURRENCY, (LPWSTR) &fmt->PositiveOrder, sizeof(UINT));
+ GetLocaleInfoEx(windowsLocaleName, LOCALE_RETURN_NUMBER|LOCALE_INEGCURR, (LPWSTR) &fmt->NegativeOrder, sizeof(UINT));
+ GetLocaleInfoEx(windowsLocaleName, LOCALE_RETURN_NUMBER|LOCALE_ICURRENCY, (LPWSTR) &fmt->PositiveOrder, sizeof(UINT));
fmt->lpCurrencySymbol = NEW_ARRAY(wchar_t, 8);
- GetLocaleInfoEx(windowsLocaleName, LOCALE_SCURRENCY, (LPWSTR) fmt->lpCurrencySymbol, 8);
+ GetLocaleInfoEx(windowsLocaleName, LOCALE_SCURRENCY, (LPWSTR) fmt->lpCurrencySymbol, 8);
}
static void freeCurrencyFormat(CURRENCYFMTW *fmt)
@@ -139,84 +139,84 @@ static void freeCurrencyFormat(CURRENCYFMTW *fmt)
}
}
-// TODO: This is copied in both winnmfmt.cpp and windtfmt.cpp, but really should
-// be factored out into a common helper for both.
-static UErrorCode GetEquivalentWindowsLocaleName(const Locale& locale, UnicodeString** buffer)
-{
- UErrorCode status = U_ZERO_ERROR;
- char asciiBCP47Tag[LOCALE_NAME_MAX_LENGTH] = {};
-
- // Convert from names like "en_CA" and "de_DE@collation=phonebook" to "en-CA" and "de-DE-u-co-phonebk".
- (void) uloc_toLanguageTag(locale.getName(), asciiBCP47Tag, UPRV_LENGTHOF(asciiBCP47Tag), FALSE, &status);
-
- if (U_SUCCESS(status))
- {
- // Need it to be UTF-16, not 8-bit
- // TODO: This seems like a good thing for a helper
- wchar_t bcp47Tag[LOCALE_NAME_MAX_LENGTH] = {};
- int32_t i;
- for (i = 0; i < UPRV_LENGTHOF(bcp47Tag); i++)
- {
- if (asciiBCP47Tag[i] == '\0')
- {
- break;
- }
- else
- {
- // normally just copy the character
- bcp47Tag[i] = static_cast<wchar_t>(asciiBCP47Tag[i]);
- }
- }
-
- // Ensure it's null terminated
- if (i < (UPRV_LENGTHOF(bcp47Tag) - 1))
- {
- bcp47Tag[i] = L'\0';
- }
- else
- {
- // Ran out of room.
- bcp47Tag[UPRV_LENGTHOF(bcp47Tag) - 1] = L'\0';
- }
-
-
- wchar_t windowsLocaleName[LOCALE_NAME_MAX_LENGTH] = {};
-
- // Note: On Windows versions below 10, there is no support for locale name aliases.
- // This means that it will fail for locales where ICU has a completely different
- // name (like ku vs ckb), and it will also not work for alternate sort locale
- // names like "de-DE-u-co-phonebk".
-
- // TODO: We could add some sort of exception table for cases like ku vs ckb.
-
- int length = ResolveLocaleName(bcp47Tag, windowsLocaleName, UPRV_LENGTHOF(windowsLocaleName));
-
- if (length > 0)
- {
- *buffer = new UnicodeString(windowsLocaleName);
- }
- else
- {
- status = U_UNSUPPORTED_ERROR;
- }
- }
- return status;
-}
-
+// TODO: This is copied in both winnmfmt.cpp and windtfmt.cpp, but really should
+// be factored out into a common helper for both.
+static UErrorCode GetEquivalentWindowsLocaleName(const Locale& locale, UnicodeString** buffer)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ char asciiBCP47Tag[LOCALE_NAME_MAX_LENGTH] = {};
+
+ // Convert from names like "en_CA" and "de_DE@collation=phonebook" to "en-CA" and "de-DE-u-co-phonebk".
+ (void) uloc_toLanguageTag(locale.getName(), asciiBCP47Tag, UPRV_LENGTHOF(asciiBCP47Tag), FALSE, &status);
+
+ if (U_SUCCESS(status))
+ {
+ // Need it to be UTF-16, not 8-bit
+ // TODO: This seems like a good thing for a helper
+ wchar_t bcp47Tag[LOCALE_NAME_MAX_LENGTH] = {};
+ int32_t i;
+ for (i = 0; i < UPRV_LENGTHOF(bcp47Tag); i++)
+ {
+ if (asciiBCP47Tag[i] == '\0')
+ {
+ break;
+ }
+ else
+ {
+ // normally just copy the character
+ bcp47Tag[i] = static_cast<wchar_t>(asciiBCP47Tag[i]);
+ }
+ }
+
+ // Ensure it's null terminated
+ if (i < (UPRV_LENGTHOF(bcp47Tag) - 1))
+ {
+ bcp47Tag[i] = L'\0';
+ }
+ else
+ {
+ // Ran out of room.
+ bcp47Tag[UPRV_LENGTHOF(bcp47Tag) - 1] = L'\0';
+ }
+
+
+ wchar_t windowsLocaleName[LOCALE_NAME_MAX_LENGTH] = {};
+
+ // Note: On Windows versions below 10, there is no support for locale name aliases.
+ // This means that it will fail for locales where ICU has a completely different
+ // name (like ku vs ckb), and it will also not work for alternate sort locale
+ // names like "de-DE-u-co-phonebk".
+
+ // TODO: We could add some sort of exception table for cases like ku vs ckb.
+
+ int length = ResolveLocaleName(bcp47Tag, windowsLocaleName, UPRV_LENGTHOF(windowsLocaleName));
+
+ if (length > 0)
+ {
+ *buffer = new UnicodeString(windowsLocaleName);
+ }
+ else
+ {
+ status = U_UNSUPPORTED_ERROR;
+ }
+ }
+ return status;
+}
+
Win32NumberFormat::Win32NumberFormat(const Locale &locale, UBool currency, UErrorCode &status)
- : NumberFormat(), fCurrency(currency), fFormatInfo(NULL), fFractionDigitsSet(FALSE), fWindowsLocaleName(nullptr)
+ : NumberFormat(), fCurrency(currency), fFormatInfo(NULL), fFractionDigitsSet(FALSE), fWindowsLocaleName(nullptr)
{
if (!U_FAILURE(status)) {
fLCID = locale.getLCID();
- GetEquivalentWindowsLocaleName(locale, &fWindowsLocaleName);
- // Note: In the previous code, it would look up the LCID for the locale, and if
- // the locale was not recognized then it would get an LCID of 0, which is a
- // synonym for LOCALE_USER_DEFAULT on Windows.
- // If the above method fails, then fWindowsLocaleName will remain as nullptr, and
- // then we will pass nullptr to API GetLocaleInfoEx, which is the same as passing
- // LOCALE_USER_DEFAULT.
-
+ GetEquivalentWindowsLocaleName(locale, &fWindowsLocaleName);
+ // Note: In the previous code, it would look up the LCID for the locale, and if
+ // the locale was not recognized then it would get an LCID of 0, which is a
+ // synonym for LOCALE_USER_DEFAULT on Windows.
+ // If the above method fails, then fWindowsLocaleName will remain as nullptr, and
+ // then we will pass nullptr to API GetLocaleInfoEx, which is the same as passing
+ // LOCALE_USER_DEFAULT.
+
// Resolve actual locale to be used later
UErrorCode tmpsts = U_ZERO_ERROR;
char tmpLocID[ULOC_FULLNAME_CAPACITY];
@@ -226,19 +226,19 @@ Win32NumberFormat::Win32NumberFormat(const Locale &locale, UBool currency, UErro
fLocale = Locale((const char*)tmpLocID);
}
- const wchar_t *localeName = nullptr;
-
- if (fWindowsLocaleName != nullptr)
- {
- localeName = reinterpret_cast<const wchar_t*>(toOldUCharPtr(fWindowsLocaleName->getTerminatedBuffer()));
- }
-
+ const wchar_t *localeName = nullptr;
+
+ if (fWindowsLocaleName != nullptr)
+ {
+ localeName = reinterpret_cast<const wchar_t*>(toOldUCharPtr(fWindowsLocaleName->getTerminatedBuffer()));
+ }
+
fFormatInfo = (FormatInfo*)uprv_malloc(sizeof(FormatInfo));
if (fCurrency) {
- getCurrencyFormat(&fFormatInfo->currency, localeName);
+ getCurrencyFormat(&fFormatInfo->currency, localeName);
} else {
- getNumberFormat(&fFormatInfo->number, localeName);
+ getNumberFormat(&fFormatInfo->number, localeName);
}
}
}
@@ -263,7 +263,7 @@ Win32NumberFormat::~Win32NumberFormat()
uprv_free(fFormatInfo);
}
- delete fWindowsLocaleName;
+ delete fWindowsLocaleName;
}
Win32NumberFormat &Win32NumberFormat::operator=(const Win32NumberFormat &other)
@@ -274,42 +274,42 @@ Win32NumberFormat &Win32NumberFormat::operator=(const Win32NumberFormat &other)
this->fLocale = other.fLocale;
this->fLCID = other.fLCID;
this->fFractionDigitsSet = other.fFractionDigitsSet;
- this->fWindowsLocaleName = other.fWindowsLocaleName == NULL ? NULL : new UnicodeString(*other.fWindowsLocaleName);
-
- const wchar_t *localeName = nullptr;
-
- if (fWindowsLocaleName != nullptr)
- {
- localeName = reinterpret_cast<const wchar_t*>(toOldUCharPtr(fWindowsLocaleName->getTerminatedBuffer()));
- }
-
+ this->fWindowsLocaleName = other.fWindowsLocaleName == NULL ? NULL : new UnicodeString(*other.fWindowsLocaleName);
+
+ const wchar_t *localeName = nullptr;
+
+ if (fWindowsLocaleName != nullptr)
+ {
+ localeName = reinterpret_cast<const wchar_t*>(toOldUCharPtr(fWindowsLocaleName->getTerminatedBuffer()));
+ }
+
if (fCurrency) {
freeCurrencyFormat(&fFormatInfo->currency);
- getCurrencyFormat(&fFormatInfo->currency, localeName);
+ getCurrencyFormat(&fFormatInfo->currency, localeName);
} else {
freeNumberFormat(&fFormatInfo->number);
- getNumberFormat(&fFormatInfo->number, localeName);
+ getNumberFormat(&fFormatInfo->number, localeName);
}
return *this;
}
-Win32NumberFormat *Win32NumberFormat::clone() const
+Win32NumberFormat *Win32NumberFormat::clone() const
{
return new Win32NumberFormat(*this);
}
-UnicodeString& Win32NumberFormat::format(double number, UnicodeString& appendTo, FieldPosition& /* pos */) const
+UnicodeString& Win32NumberFormat::format(double number, UnicodeString& appendTo, FieldPosition& /* pos */) const
{
return format(getMaximumFractionDigits(), appendTo, L"%.16f", number);
}
-UnicodeString& Win32NumberFormat::format(int32_t number, UnicodeString& appendTo, FieldPosition& /* pos */) const
+UnicodeString& Win32NumberFormat::format(int32_t number, UnicodeString& appendTo, FieldPosition& /* pos */) const
{
return format(getMinimumFractionDigits(), appendTo, L"%I32d", number);
}
-UnicodeString& Win32NumberFormat::format(int64_t number, UnicodeString& appendTo, FieldPosition& /* pos */) const
+UnicodeString& Win32NumberFormat::format(int64_t number, UnicodeString& appendTo, FieldPosition& /* pos */) const
{
return format(getMinimumFractionDigits(), appendTo, L"%I64d", number);
}
@@ -389,13 +389,13 @@ UnicodeString &Win32NumberFormat::format(int32_t numDigits, UnicodeString &appen
formatInfo = *fFormatInfo;
buffer[0] = 0x0000;
- const wchar_t *localeName = nullptr;
-
- if (fWindowsLocaleName != nullptr)
- {
- localeName = reinterpret_cast<const wchar_t*>(toOldUCharPtr(fWindowsLocaleName->getTerminatedBuffer()));
- }
-
+ const wchar_t *localeName = nullptr;
+
+ if (fWindowsLocaleName != nullptr)
+ {
+ localeName = reinterpret_cast<const wchar_t*>(toOldUCharPtr(fWindowsLocaleName->getTerminatedBuffer()));
+ }
+
if (fCurrency) {
if (fFractionDigitsSet) {
formatInfo.currency.NumDigits = (UINT) numDigits;
@@ -405,17 +405,17 @@ UnicodeString &Win32NumberFormat::format(int32_t numDigits, UnicodeString &appen
formatInfo.currency.Grouping = 0;
}
- result = GetCurrencyFormatEx(localeName, 0, nBuffer, &formatInfo.currency, buffer, STACK_BUFFER_SIZE);
+ result = GetCurrencyFormatEx(localeName, 0, nBuffer, &formatInfo.currency, buffer, STACK_BUFFER_SIZE);
if (result == 0) {
DWORD lastError = GetLastError();
if (lastError == ERROR_INSUFFICIENT_BUFFER) {
- int newLength = GetCurrencyFormatEx(localeName, 0, nBuffer, &formatInfo.currency, NULL, 0);
+ int newLength = GetCurrencyFormatEx(localeName, 0, nBuffer, &formatInfo.currency, NULL, 0);
buffer = NEW_ARRAY(wchar_t, newLength);
buffer[0] = 0x0000;
- GetCurrencyFormatEx(localeName, 0, nBuffer, &formatInfo.currency, buffer, newLength);
+ GetCurrencyFormatEx(localeName, 0, nBuffer, &formatInfo.currency, buffer, newLength);
}
}
} else {
@@ -427,15 +427,15 @@ UnicodeString &Win32NumberFormat::format(int32_t numDigits, UnicodeString &appen
formatInfo.number.Grouping = 0;
}
- result = GetNumberFormatEx(localeName, 0, nBuffer, &formatInfo.number, buffer, STACK_BUFFER_SIZE);
+ result = GetNumberFormatEx(localeName, 0, nBuffer, &formatInfo.number, buffer, STACK_BUFFER_SIZE);
if (result == 0) {
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
- int newLength = GetNumberFormatEx(localeName, 0, nBuffer, &formatInfo.number, NULL, 0);
+ int newLength = GetNumberFormatEx(localeName, 0, nBuffer, &formatInfo.number, NULL, 0);
buffer = NEW_ARRAY(wchar_t, newLength);
buffer[0] = 0x0000;
- GetNumberFormatEx(localeName, 0, nBuffer, &formatInfo.number, buffer, newLength);
+ GetNumberFormatEx(localeName, 0, nBuffer, &formatInfo.number, buffer, newLength);
}
}
}
diff --git a/contrib/libs/icu/i18n/winnmfmt.h b/contrib/libs/icu/i18n/winnmfmt.h
index 99571d2013..33ddefc624 100644
--- a/contrib/libs/icu/i18n/winnmfmt.h
+++ b/contrib/libs/icu/i18n/winnmfmt.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
********************************************************************************
@@ -44,7 +44,7 @@ public:
virtual ~Win32NumberFormat();
- virtual Win32NumberFormat *clone() const;
+ virtual Win32NumberFormat *clone() const;
Win32NumberFormat &operator=(const Win32NumberFormat &other);
@@ -128,7 +128,7 @@ public:
* <pre>
* . Base* polymorphic_pointer = createPolymorphicObject();
* . if (polymorphic_pointer->getDynamicClassID() ==
- * . derived::getStaticClassID()) ...
+ * . derived::getStaticClassID()) ...
* </pre>
* @return The class ID for all objects of this class.
*/
@@ -155,7 +155,7 @@ private:
FormatInfo *fFormatInfo;
UBool fFractionDigitsSet;
- UnicodeString* fWindowsLocaleName; // Stores the equivalent Windows locale name.
+ UnicodeString* fWindowsLocaleName; // Stores the equivalent Windows locale name.
};
U_NAMESPACE_END
diff --git a/contrib/libs/icu/i18n/wintzimpl.cpp b/contrib/libs/icu/i18n/wintzimpl.cpp
index 433ed4c293..7449fa6e4c 100644
--- a/contrib/libs/icu/i18n/wintzimpl.cpp
+++ b/contrib/libs/icu/i18n/wintzimpl.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
********************************************************************************
@@ -13,7 +13,7 @@
#include "unicode/utypes.h"
-#if U_PLATFORM_USES_ONLY_WIN32_API && !UCONFIG_NO_FORMATTING
+#if U_PLATFORM_USES_ONLY_WIN32_API && !UCONFIG_NO_FORMATTING
#include "wintzimpl.h"
@@ -24,9 +24,9 @@
#include "uassert.h"
#include "cmemory.h"
-#ifndef WIN32_LEAN_AND_MEAN
+#ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
-#endif
+#endif
# define VC_EXTRALEAN
# define NOUSER
# define NOSERVICE
@@ -65,12 +65,12 @@ static UBool getSystemTimeInformation(TimeZone *tz, SYSTEMTIME &daylightDate, SY
// Always use DOW type rule
int32_t hour, min, sec, mil;
standardDate.wYear = 0;
- standardDate.wMonth = static_cast<WORD>(std->getRule()->getRuleMonth()) + 1;
- standardDate.wDay = static_cast<WORD>(std->getRule()->getRuleWeekInMonth());
+ standardDate.wMonth = static_cast<WORD>(std->getRule()->getRuleMonth()) + 1;
+ standardDate.wDay = static_cast<WORD>(std->getRule()->getRuleWeekInMonth());
if (standardDate.wDay < 0) {
standardDate.wDay = 5;
}
- standardDate.wDayOfWeek = static_cast<WORD>(std->getRule()->getRuleDayOfWeek()) - 1;
+ standardDate.wDayOfWeek = static_cast<WORD>(std->getRule()->getRuleDayOfWeek()) - 1;
mil = std->getRule()->getRuleMillisInDay();
hour = mil/3600000;
@@ -80,18 +80,18 @@ static UBool getSystemTimeInformation(TimeZone *tz, SYSTEMTIME &daylightDate, SY
sec = mil/1000;
mil %= 1000;
- standardDate.wHour = static_cast<WORD>(hour);
- standardDate.wMinute = static_cast<WORD>(min);
- standardDate.wSecond = static_cast<WORD>(sec);
- standardDate.wMilliseconds = static_cast<WORD>(mil);
+ standardDate.wHour = static_cast<WORD>(hour);
+ standardDate.wMinute = static_cast<WORD>(min);
+ standardDate.wSecond = static_cast<WORD>(sec);
+ standardDate.wMilliseconds = static_cast<WORD>(mil);
daylightDate.wYear = 0;
- daylightDate.wMonth = static_cast<WORD>(dst->getRule()->getRuleMonth()) + 1;
- daylightDate.wDay = static_cast<WORD>(dst->getRule()->getRuleWeekInMonth());
+ daylightDate.wMonth = static_cast<WORD>(dst->getRule()->getRuleMonth()) + 1;
+ daylightDate.wDay = static_cast<WORD>(dst->getRule()->getRuleWeekInMonth());
if (daylightDate.wDay < 0) {
daylightDate.wDay = 5;
}
- daylightDate.wDayOfWeek = static_cast<WORD>(dst->getRule()->getRuleDayOfWeek()) - 1;
+ daylightDate.wDayOfWeek = static_cast<WORD>(dst->getRule()->getRuleDayOfWeek()) - 1;
mil = dst->getRule()->getRuleMillisInDay();
hour = mil/3600000;
@@ -101,10 +101,10 @@ static UBool getSystemTimeInformation(TimeZone *tz, SYSTEMTIME &daylightDate, SY
sec = mil/1000;
mil %= 1000;
- daylightDate.wHour = static_cast<WORD>(hour);
- daylightDate.wMinute = static_cast<WORD>(min);
- daylightDate.wSecond = static_cast<WORD>(sec);
- daylightDate.wMilliseconds = static_cast<WORD>(mil);
+ daylightDate.wHour = static_cast<WORD>(hour);
+ daylightDate.wMinute = static_cast<WORD>(min);
+ daylightDate.wSecond = static_cast<WORD>(sec);
+ daylightDate.wMilliseconds = static_cast<WORD>(mil);
}
} else {
result = FALSE;
diff --git a/contrib/libs/icu/i18n/wintzimpl.h b/contrib/libs/icu/i18n/wintzimpl.h
index 772ea95bc5..9f982ebe4e 100644
--- a/contrib/libs/icu/i18n/wintzimpl.h
+++ b/contrib/libs/icu/i18n/wintzimpl.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
********************************************************************************
@@ -16,7 +16,7 @@
#include "unicode/utypes.h"
-#if U_PLATFORM_USES_ONLY_WIN32_API
+#if U_PLATFORM_USES_ONLY_WIN32_API
/**
* \file
* \brief C API: Utilities for dealing w/ Windows time zones.
@@ -34,6 +34,6 @@ U_CAPI UBool U_EXPORT2
uprv_getWindowsTimeZoneInfo(TIME_ZONE_INFORMATION *zoneInfo, const UChar *icuid, int32_t length);
-#endif /* U_PLATFORM_USES_ONLY_WIN32_API */
+#endif /* U_PLATFORM_USES_ONLY_WIN32_API */
#endif /* __WINTZIMPL */
diff --git a/contrib/libs/icu/i18n/zonemeta.cpp b/contrib/libs/icu/i18n/zonemeta.cpp
index 72c590f424..b2c6abeff0 100644
--- a/contrib/libs/icu/i18n/zonemeta.cpp
+++ b/contrib/libs/icu/i18n/zonemeta.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -17,7 +17,7 @@
#include "unicode/ustring.h"
#include "unicode/putil.h"
#include "unicode/simpletz.h"
-#include "unicode/strenum.h"
+#include "unicode/strenum.h"
#include "umutex.h"
#include "uvector.h"
#include "cmemory.h"
@@ -28,9 +28,9 @@
#include "uresimp.h"
#include "uhash.h"
#include "olsontz.h"
-#include "uinvchar.h"
+#include "uinvchar.h"
-static icu::UMutex gZoneMetaLock;
+static icu::UMutex gZoneMetaLock;
// CLDR Canonical ID mapping table
static UHashtable *gCanonicalIDCache = NULL;
@@ -256,12 +256,12 @@ ZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UErrorCode& status) {
tzid.extract(utzid, ZID_KEY_MAX + 1, tmpStatus);
U_ASSERT(tmpStatus == U_ZERO_ERROR); // we checked the length of tzid already
- if (!uprv_isInvariantUString(utzid, -1)) {
- // All of known tz IDs are only containing ASCII invariant characters.
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return NULL;
- }
-
+ if (!uprv_isInvariantUString(utzid, -1)) {
+ // All of known tz IDs are only containing ASCII invariant characters.
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+
// Check if it was already cached
umtx_lock(&gZoneMetaLock);
{
@@ -319,10 +319,10 @@ ZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UErrorCode& status) {
id[len] = (char) 0; // Make sure it is null terminated.
// replace '/' with ':'
- char *q = id;
- while (*q++) {
- if (*q == '/') {
- *q = ':';
+ char *q = id;
+ while (*q++) {
+ if (*q == '/') {
+ *q = ':';
}
}
@@ -690,7 +690,7 @@ ZoneMeta::createMetazoneMappings(const UnicodeString &tzid) {
mzMappings = new UVector(deleteOlsonToMetaMappingEntry, NULL, status);
if (U_FAILURE(status)) {
delete mzMappings;
- mzMappings = NULL;
+ mzMappings = NULL;
uprv_free(entry);
break;
}
@@ -784,14 +784,14 @@ static void U_CALLCONV initAvailableMetaZoneIDs () {
UResourceBundle *rb = ures_openDirect(NULL, gMetaZones, &status);
UResourceBundle *bundle = ures_getByKey(rb, gMapTimezonesTag, NULL, &status);
- StackUResourceBundle res;
+ StackUResourceBundle res;
while (U_SUCCESS(status) && ures_hasNext(bundle)) {
- ures_getNextResource(bundle, res.getAlias(), &status);
+ ures_getNextResource(bundle, res.getAlias(), &status);
if (U_FAILURE(status)) {
break;
}
- const char *mzID = ures_getKey(res.getAlias());
- int32_t len = static_cast<int32_t>(uprv_strlen(mzID));
+ const char *mzID = ures_getKey(res.getAlias());
+ int32_t len = static_cast<int32_t>(uprv_strlen(mzID));
UChar *uMzID = (UChar*)uprv_malloc(sizeof(UChar) * (len + 1));
if (uMzID == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
@@ -848,13 +848,13 @@ ZoneMeta::createCustomTimeZone(int32_t offset) {
negative = TRUE;
tmp = -offset;
}
- uint8_t hour, min, sec;
+ uint8_t hour, min, sec;
tmp /= 1000;
- sec = static_cast<uint8_t>(tmp % 60);
+ sec = static_cast<uint8_t>(tmp % 60);
tmp /= 60;
- min = static_cast<uint8_t>(tmp % 60);
- hour = static_cast<uint8_t>(tmp / 60);
+ min = static_cast<uint8_t>(tmp % 60);
+ hour = static_cast<uint8_t>(tmp / 60);
UnicodeString zid;
formatCustomID(hour, min, sec, negative, zid);
diff --git a/contrib/libs/icu/i18n/zonemeta.h b/contrib/libs/icu/i18n/zonemeta.h
index 9dbcc878a2..0c92047918 100644
--- a/contrib/libs/icu/i18n/zonemeta.h
+++ b/contrib/libs/icu/i18n/zonemeta.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
@@ -41,11 +41,11 @@ public:
/**
* Return the canonical id for this tzid defined by CLDR, which might be the id itself.
* This overload method returns a persistent const UChar*, which is guranteed to persist
- * (a pointer to a resource). If the given system tzid is not known, U_ILLEGAL_ARGUMENT_ERROR
- * is set in the status.
- * @param tzid Zone ID
- * @param status Receives the status
- * @return The canonical ID for the input time zone ID
+ * (a pointer to a resource). If the given system tzid is not known, U_ILLEGAL_ARGUMENT_ERROR
+ * is set in the status.
+ * @param tzid Zone ID
+ * @param status Receives the status
+ * @return The canonical ID for the input time zone ID
*/
static const UChar* U_EXPORT2 getCanonicalCLDRID(const UnicodeString &tzid, UErrorCode& status);
diff --git a/contrib/libs/icu/i18n/zrule.cpp b/contrib/libs/icu/i18n/zrule.cpp
index bdf84965b5..83bf019923 100644
--- a/contrib/libs/icu/i18n/zrule.cpp
+++ b/contrib/libs/icu/i18n/zrule.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/zrule.h b/contrib/libs/icu/i18n/zrule.h
index f395ad4c3f..04a4ecead9 100644
--- a/contrib/libs/icu/i18n/zrule.h
+++ b/contrib/libs/icu/i18n/zrule.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/ztrans.cpp b/contrib/libs/icu/i18n/ztrans.cpp
index 9dbe9bb0b9..3e7fe95817 100644
--- a/contrib/libs/icu/i18n/ztrans.cpp
+++ b/contrib/libs/icu/i18n/ztrans.cpp
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
diff --git a/contrib/libs/icu/i18n/ztrans.h b/contrib/libs/icu/i18n/ztrans.h
index b23bb4fc70..60552df017 100644
--- a/contrib/libs/icu/i18n/ztrans.h
+++ b/contrib/libs/icu/i18n/ztrans.h
@@ -1,4 +1,4 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************