1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813 |
- // © 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_roundingutils.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 {};
- 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-odd", STEM_ROUNDING_MODE_HALF_ODD, status);
- b.add(u"rounding-mode-half-ceiling", STEM_ROUNDING_MODE_HALF_CEILING, status);
- b.add(u"rounding-mode-half-floor", STEM_ROUNDING_MODE_HALF_FLOOR, 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"integer-width-trunc", STEM_INTEGER_WIDTH_TRUNC, 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-formal", STEM_UNIT_WIDTH_FORMAL, status);
- b.add(u"unit-width-variant", STEM_UNIT_WIDTH_VARIANT, 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"sign-negative", STEM_SIGN_NEGATIVE, status);
- b.add(u"sign-accounting-negative", STEM_SIGN_ACCOUNTING_NEGATIVE, 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"usage", STEM_UNIT_USAGE, 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);
- b.add(u"+-", STEM_SIGN_NEGATIVE, status);
- b.add(u"()-", STEM_SIGN_ACCOUNTING_NEGATIVE, 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
- } // 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_EXIT;
- }
- }
- MeasureUnit stem_to_object::unit(skeleton::StemEnum stem) {
- switch (stem) {
- case STEM_BASE_UNIT:
- return MeasureUnit();
- case STEM_PERCENT:
- return MeasureUnit::getPercent();
- case STEM_PERMILLE:
- return MeasureUnit::getPermille();
- default:
- UPRV_UNREACHABLE_EXIT;
- }
- }
- 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_EXIT;
- }
- }
- 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_ODD:
- return UNUM_ROUND_HALF_ODD;
- case STEM_ROUNDING_MODE_HALF_CEILING:
- return UNUM_ROUND_HALF_CEILING;
- case STEM_ROUNDING_MODE_HALF_FLOOR:
- return UNUM_ROUND_HALF_FLOOR;
- 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_EXIT;
- }
- }
- 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_FORMAL:
- return UNUM_UNIT_WIDTH_FORMAL;
- case STEM_UNIT_WIDTH_VARIANT:
- return UNUM_UNIT_WIDTH_VARIANT;
- 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;
- case STEM_SIGN_NEGATIVE:
- return UNUM_SIGN_NEGATIVE;
- case STEM_SIGN_ACCOUNTING_NEGATIVE:
- return UNUM_SIGN_ACCOUNTING_NEGATIVE;
- 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_HALF_ODD:
- sb.append(u"rounding-mode-half-odd", -1);
- break;
- case UNUM_ROUND_HALF_CEILING:
- sb.append(u"rounding-mode-half-ceiling", -1);
- break;
- case UNUM_ROUND_HALF_FLOOR:
- sb.append(u"rounding-mode-half-floor", -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_EXIT;
- }
- }
- 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_EXIT;
- }
- }
- 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_FORMAL:
- sb.append(u"unit-width-formal", -1);
- break;
- case UNUM_UNIT_WIDTH_VARIANT:
- sb.append(u"unit-width-variant", -1);
- break;
- case UNUM_UNIT_WIDTH_HIDDEN:
- sb.append(u"unit-width-hidden", -1);
- break;
- default:
- UPRV_UNREACHABLE_EXIT;
- }
- }
- 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;
- case UNUM_SIGN_NEGATIVE:
- sb.append(u"sign-negative", -1);
- break;
- case UNUM_SIGN_ACCOUNTING_NEGATIVE:
- sb.append(u"sign-accounting-negative", -1);
- break;
- default:
- UPRV_UNREACHABLE_EXIT;
- }
- }
- 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_EXIT;
- }
- }
- 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));
- U_ASSERT(kSerializedStemTrie != nullptr);
- // 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_UNIT_USAGE:
- 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) {
- U_ASSERT(U_SUCCESS(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_PRECISION;
- 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_PRECISION;
- }
- 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_ODD:
- case STEM_ROUNDING_MODE_HALF_CEILING:
- case STEM_ROUNDING_MODE_HALF_FLOOR:
- 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_INTEGER_WIDTH_TRUNC:
- CHECK_NULL(seen, integerWidth, status);
- macros.integerWidth = IntegerWidth::zeroFillTo(0).truncateAt(0);
- 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_FORMAL:
- case STEM_UNIT_WIDTH_VARIANT:
- 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:
- case STEM_SIGN_NEGATIVE:
- case STEM_SIGN_ACCOUNTING_NEGATIVE:
- 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_UNIT_USAGE:
- CHECK_NULL(seen, usage, status);
- return STATE_UNIT_USAGE;
- case STEM_CURRENCY:
- CHECK_NULL(seen, unit, status);
- CHECK_NULL(seen, perUnit, 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_EXIT;
- }
- }
- ParseState skeleton::parseOption(ParseState stem, const StringSegment& segment, MacroProps& macros,
- UErrorCode& status) {
- U_ASSERT(U_SUCCESS(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_UNIT_USAGE:
- blueprint_helpers::parseUnitUsageOption(segment, macros, status);
- return STATE_NULL;
- case STATE_INCREMENT_PRECISION:
- blueprint_helpers::parseIncrementOption(segment, macros, status);
- return STATE_PRECISION;
- 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_PRECISION;
- }
- if (U_FAILURE(status)) {
- return {};
- }
- // If the fracSig option was not found, try normal precision options.
- stem = STATE_PRECISION;
- break;
- default:
- break;
- }
- // Trailing zeros option
- switch (stem) {
- case STATE_PRECISION:
- if (blueprint_helpers::parseTrailingZeroOption(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::usage(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.unitDisplayCase.isSet()) {
- 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 char16_t* 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) {
- U_ASSERT(U_SUCCESS(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 <-> char16_t conversion...
- 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 (Aug 2020) is "volume", which has 33 units.
- static constexpr int32_t CAPACITY = 40;
- 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::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 <-> char16_t conversion...
- U_ASSERT(U_SUCCESS(status));
- CharString buffer;
- SKELETON_UCHAR_TO_CHAR(buffer, segment.toTempUnicodeString(), 0, segment.length(), status);
- ErrorCode internalStatus;
- macros.unit = MeasureUnit::forIdentifier(buffer.toStringPiece(), internalStatus);
- if (internalStatus.isFailure()) {
- // throw new SkeletonSyntaxException("Invalid core unit identifier", segment, e);
- status = U_NUMBER_SKELETON_SYNTAX_ERROR;
- return;
- }
- }
- void blueprint_helpers::parseUnitUsageOption(const StringSegment &segment, MacroProps ¯os,
- UErrorCode &status) {
- // Need to do char <-> char16_t conversion...
- U_ASSERT(U_SUCCESS(status));
- CharString buffer;
- SKELETON_UCHAR_TO_CHAR(buffer, segment.toTempUnicodeString(), 0, segment.length(), status);
- macros.usage.set(buffer.toStringPiece());
- // We do not do any validation of the usage string: it depends on the
- // unitPreferenceData in the units resources.
- }
- 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 {
- // NOTE: Other sign displays are not included because they aren't useful in this context
- 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;
- }
- }
- 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;
- }
- auto& oldPrecision = static_cast<const FractionPrecision&>(macros.precision);
- if (offset < segment.length()) {
- UNumberRoundingPriority priority;
- if (maxSig == -1) {
- // The wildcard character is not allowed with the priority annotation
- status = U_NUMBER_SKELETON_SYNTAX_ERROR;
- return false;
- }
- if (segment.codePointAt(offset) == u'r') {
- priority = UNUM_ROUNDING_PRIORITY_RELAXED;
- offset++;
- } else if (segment.codePointAt(offset) == u's') {
- priority = UNUM_ROUNDING_PRIORITY_STRICT;
- offset++;
- } else {
- // Invalid digits option for fraction rounder
- status = U_NUMBER_SKELETON_SYNTAX_ERROR;
- return false;
- }
- if (offset < segment.length()) {
- // Invalid digits option for fraction rounder
- status = U_NUMBER_SKELETON_SYNTAX_ERROR;
- return false;
- }
- macros.precision = oldPrecision.withSignificantDigits(minSig, maxSig, priority);
- } else if (maxSig == -1) {
- // withMinDigits
- macros.precision = oldPrecision.withMinDigits(minSig);
- } else if (minSig == 1) {
- // withMaxDigits
- macros.precision = oldPrecision.withMaxDigits(maxSig);
- } else {
- // Digits options with both min and max sig require the priority option
- status = U_NUMBER_SKELETON_SYNTAX_ERROR;
- return false;
- }
- return true;
- }
- bool blueprint_helpers::parseTrailingZeroOption(const StringSegment& segment, MacroProps& macros, UErrorCode&) {
- if (segment == u"w") {
- macros.precision = macros.precision.trailingZeroDisplay(UNUM_TRAILING_ZERO_HIDE_IF_WHOLE);
- return true;
- }
- return false;
- }
- void blueprint_helpers::parseIncrementOption(const StringSegment &segment, MacroProps ¯os,
- UErrorCode &status) {
- number::impl::parseIncrementOption(segment, macros.precision, status);
- }
- void blueprint_helpers::generateIncrementOption(
- uint32_t increment,
- digits_t incrementMagnitude,
- int32_t minFrac,
- UnicodeString& sb,
- UErrorCode&) {
- // Utilize DecimalQuantity/double_conversion to format this for us.
- DecimalQuantity dq;
- dq.setToLong(increment);
- dq.adjustMagnitude(incrementMagnitude);
- dq.setMinFraction(minFrac);
- sb.append(dq.toPlainString());
- }
- 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 <-> char16_t 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 <-> char16_t conversion...
- sb.append(UnicodeString(ns.getName(), -1, US_INV));
- }
- void blueprint_helpers::parseScaleOption(const StringSegment& segment, MacroProps& macros,
- UErrorCode& status) {
- // Need to do char <-> char16_t 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) || decnum->isSpecial()) {
- // 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) {
- MeasureUnit unit = macros.unit;
- if (!utils::unitIsBaseUnit(macros.perUnit)) {
- if (utils::unitIsCurrency(macros.unit) || utils::unitIsCurrency(macros.perUnit)) {
- status = U_UNSUPPORTED_ERROR;
- return false;
- }
- unit = unit.product(macros.perUnit.reciprocal(status), status);
- }
- if (utils::unitIsCurrency(unit)) {
- sb.append(u"currency/", -1);
- CurrencyUnit currency(unit, status);
- if (U_FAILURE(status)) {
- return false;
- }
- blueprint_helpers::generateCurrencyOption(currency, sb, status);
- return true;
- } else if (utils::unitIsBaseUnit(unit)) {
- // Default value is not shown in normalized form
- return false;
- } else if (utils::unitIsPercent(unit)) {
- sb.append(u"percent", -1);
- return true;
- } else if (utils::unitIsPermille(unit)) {
- sb.append(u"permille", -1);
- return true;
- } else {
- sb.append(u"unit/", -1);
- sb.append(unit.getIdentifier());
- return true;
- }
- }
- bool GeneratorHelpers::usage(const MacroProps& macros, UnicodeString& sb, UErrorCode& /* status */) {
- if (macros.usage.isSet()) {
- sb.append(u"usage/", -1);
- sb.append(UnicodeString(macros.usage.fValue, -1, US_INV));
- return true;
- }
- return false;
- }
- 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.fRetain) {
- if (impl.fPriority == UNUM_ROUNDING_PRIORITY_RELAXED) {
- // withMinDigits
- blueprint_helpers::generateDigitsStem(impl.fMaxSig, -1, sb, status);
- } else {
- // withMaxDigits
- blueprint_helpers::generateDigitsStem(1, impl.fMaxSig, sb, status);
- }
- } else {
- blueprint_helpers::generateDigitsStem(impl.fMinSig, impl.fMaxSig, sb, status);
- if (impl.fPriority == UNUM_ROUNDING_PRIORITY_RELAXED) {
- sb.append(u'r');
- } else {
- sb.append(u's');
- }
- }
- } 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.fIncrementMagnitude,
- impl.fMinFrac,
- 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;
- }
- if (macros.precision.fTrailingZeroDisplay == UNUM_TRAILING_ZERO_HIDE_IF_WHOLE) {
- sb.append(u"/w", -1);
- }
- // 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;
- }
- const auto& minMaxInt = macros.integerWidth.fUnion.minMaxInt;
- if (minMaxInt.fMinInt == 0 && minMaxInt.fMaxInt == 0) {
- sb.append(u"integer-width-trunc", -1);
- return true;
- }
- sb.append(u"integer-width/", -1);
- blueprint_helpers::generateIntegerWidthOption(
- minMaxInt.fMinInt,
- 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 */
|