// Copyright (C) 2016 and later: Unicode, Inc. and others. // License & terms of use: http://www.unicode.org/copyright.html /* ******************************************************************************* * Copyright (C) 2009-2016, International Business Machines Corporation and * others. All Rights Reserved. ******************************************************************************* * * This file contains the class DecimalFormatStaticSets * * DecimalFormatStaticSets holds the UnicodeSets that are needed for lenient * parsing of decimal and group separators. ******************************************************************************** */ #include "unicode/utypes.h" #if !UCONFIG_NO_FORMATTING #include "unicode/unistr.h" #include "unicode/uniset.h" #include "unicode/uchar.h" #include "cmemory.h" #include "cstring.h" #include "uassert.h" #include "ucln_in.h" #include "umutex.h" #include "decfmtst.h" U_NAMESPACE_BEGIN //------------------------------------------------------------------------------ // // Unicode Set pattern strings for all of the required constant sets. // Initialized with hex values for portability to EBCDIC based machines. // Really ugly, but there's no good way to avoid it. // //------------------------------------------------------------------------------ static const UChar gDotEquivalentsPattern[] = { // [ . \u2024 \u3002 \uFE12 \uFE52 \uFF0E \uFF61 ] 0x005B, 0x002E, 0x2024, 0x3002, 0xFE12, 0xFE52, 0xFF0E, 0xFF61, 0x005D, 0x0000}; static const UChar gCommaEquivalentsPattern[] = { // [ , \u060C \u066B \u3001 \uFE10 \uFE11 \uFE50 \uFE51 \uFF0C \uFF64 ] 0x005B, 0x002C, 0x060C, 0x066B, 0x3001, 0xFE10, 0xFE11, 0xFE50, 0xFE51, 0xFF0C, 0xFF64, 0x005D, 0x0000}; static const UChar gOtherGroupingSeparatorsPattern[] = { // [ \ SPACE ' NBSP \u066C \u2000 - \u200A \u2018 \u2019 \u202F \u205F \u3000 \uFF07 ] 0x005B, 0x005C, 0x0020, 0x0027, 0x00A0, 0x066C, 0x2000, 0x002D, 0x200A, 0x2018, 0x2019, 0x202F, 0x205F, 0x3000, 0xFF07, 0x005D, 0x0000}; static const UChar gDashEquivalentsPattern[] = { // [ \ - HYPHEN F_DASH N_DASH MINUS ] 0x005B, 0x005C, 0x002D, 0x2010, 0x2012, 0x2013, 0x2212, 0x005D, 0x0000}; static const UChar gStrictDotEquivalentsPattern[] = { // [ . \u2024 \uFE52 \uFF0E \uFF61 ] 0x005B, 0x002E, 0x2024, 0xFE52, 0xFF0E, 0xFF61, 0x005D, 0x0000}; static const UChar gStrictCommaEquivalentsPattern[] = { // [ , \u066B \uFE10 \uFE50 \uFF0C ] 0x005B, 0x002C, 0x066B, 0xFE10, 0xFE50, 0xFF0C, 0x005D, 0x0000}; static const UChar gStrictOtherGroupingSeparatorsPattern[] = { // [ \ SPACE ' NBSP \u066C \u2000 - \u200A \u2018 \u2019 \u202F \u205F \u3000 \uFF07 ] 0x005B, 0x005C, 0x0020, 0x0027, 0x00A0, 0x066C, 0x2000, 0x002D, 0x200A, 0x2018, 0x2019, 0x202F, 0x205F, 0x3000, 0xFF07, 0x005D, 0x0000}; static const UChar gStrictDashEquivalentsPattern[] = { // [ \ - MINUS ] 0x005B, 0x005C, 0x002D, 0x2212, 0x005D, 0x0000}; static UChar32 gMinusSigns[] = { 0x002D, 0x207B, 0x208B, 0x2212, 0x2796, 0xFE63, 0xFF0D}; static UChar32 gPlusSigns[] = { 0x002B, 0x207A, 0x208A, 0x2795, 0xfB29, 0xFE62, 0xFF0B}; static void initUnicodeSet(const UChar32 *raw, int32_t len, UnicodeSet *s) { for (int32_t i = 0; i < len; ++i) { s->add(raw[i]); } } DecimalFormatStaticSets::DecimalFormatStaticSets(UErrorCode &status) : fDotEquivalents(NULL), fCommaEquivalents(NULL), fOtherGroupingSeparators(NULL), fDashEquivalents(NULL), fStrictDotEquivalents(NULL), fStrictCommaEquivalents(NULL), fStrictOtherGroupingSeparators(NULL), fStrictDashEquivalents(NULL), fDefaultGroupingSeparators(NULL), fStrictDefaultGroupingSeparators(NULL), fMinusSigns(NULL), fPlusSigns(NULL) { fDotEquivalents = new UnicodeSet(UnicodeString(TRUE, gDotEquivalentsPattern, -1), status); fCommaEquivalents = new UnicodeSet(UnicodeString(TRUE, gCommaEquivalentsPattern, -1), status); fOtherGroupingSeparators = new UnicodeSet(UnicodeString(TRUE, gOtherGroupingSeparatorsPattern, -1), status); fDashEquivalents = new UnicodeSet(UnicodeString(TRUE, gDashEquivalentsPattern, -1), status); fStrictDotEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictDotEquivalentsPattern, -1), status); fStrictCommaEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictCommaEquivalentsPattern, -1), status); fStrictOtherGroupingSeparators = new UnicodeSet(UnicodeString(TRUE, gStrictOtherGroupingSeparatorsPattern, -1), status); fStrictDashEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictDashEquivalentsPattern, -1), status); fDefaultGroupingSeparators = new UnicodeSet(*fDotEquivalents); fDefaultGroupingSeparators->addAll(*fCommaEquivalents); fDefaultGroupingSeparators->addAll(*fOtherGroupingSeparators); fStrictDefaultGroupingSeparators = new UnicodeSet(*fStrictDotEquivalents); fStrictDefaultGroupingSeparators->addAll(*fStrictCommaEquivalents); fStrictDefaultGroupingSeparators->addAll(*fStrictOtherGroupingSeparators); fMinusSigns = new UnicodeSet(); fPlusSigns = new UnicodeSet(); // Check for null pointers if (fDotEquivalents == NULL || fCommaEquivalents == NULL || fOtherGroupingSeparators == NULL || fDashEquivalents == NULL || fStrictDotEquivalents == NULL || fStrictCommaEquivalents == NULL || fStrictOtherGroupingSeparators == NULL || fStrictDashEquivalents == NULL || fDefaultGroupingSeparators == NULL || fStrictOtherGroupingSeparators == NULL || fMinusSigns == NULL || fPlusSigns == NULL) { cleanup(); status = U_MEMORY_ALLOCATION_ERROR; return; } initUnicodeSet( gMinusSigns, UPRV_LENGTHOF(gMinusSigns), fMinusSigns); initUnicodeSet( gPlusSigns, UPRV_LENGTHOF(gPlusSigns), fPlusSigns); // Freeze all the sets fDotEquivalents->freeze(); fCommaEquivalents->freeze(); fOtherGroupingSeparators->freeze(); fDashEquivalents->freeze(); fStrictDotEquivalents->freeze(); fStrictCommaEquivalents->freeze(); fStrictOtherGroupingSeparators->freeze(); fStrictDashEquivalents->freeze(); fDefaultGroupingSeparators->freeze(); fStrictDefaultGroupingSeparators->freeze(); fMinusSigns->freeze(); fPlusSigns->freeze(); } DecimalFormatStaticSets::~DecimalFormatStaticSets() { cleanup(); } void DecimalFormatStaticSets::cleanup() { // Be sure to clean up newly added fields! delete fDotEquivalents; fDotEquivalents = NULL; delete fCommaEquivalents; fCommaEquivalents = NULL; delete fOtherGroupingSeparators; fOtherGroupingSeparators = NULL; delete fDashEquivalents; fDashEquivalents = NULL; delete fStrictDotEquivalents; fStrictDotEquivalents = NULL; delete fStrictCommaEquivalents; fStrictCommaEquivalents = NULL; delete fStrictOtherGroupingSeparators; fStrictOtherGroupingSeparators = NULL; delete fStrictDashEquivalents; fStrictDashEquivalents = NULL; delete fDefaultGroupingSeparators; fDefaultGroupingSeparators = NULL; delete fStrictDefaultGroupingSeparators; fStrictDefaultGroupingSeparators = NULL; delete fStrictOtherGroupingSeparators; fStrictOtherGroupingSeparators = NULL; delete fMinusSigns; fMinusSigns = NULL; delete fPlusSigns; fPlusSigns = NULL; } static DecimalFormatStaticSets *gStaticSets; static icu::UInitOnce gStaticSetsInitOnce = U_INITONCE_INITIALIZER; //------------------------------------------------------------------------------ // // decfmt_cleanup Memory cleanup function, free/delete all // cached memory. Called by ICU's u_cleanup() function. // //------------------------------------------------------------------------------ U_CDECL_BEGIN static UBool U_CALLCONV decimfmt_cleanup(void) { delete gStaticSets; gStaticSets = NULL; gStaticSetsInitOnce.reset(); return TRUE; } static void U_CALLCONV initSets(UErrorCode &status) { U_ASSERT(gStaticSets == NULL); ucln_i18n_registerCleanup(UCLN_I18N_DECFMT, decimfmt_cleanup); gStaticSets = new DecimalFormatStaticSets(status); if (U_FAILURE(status)) { delete gStaticSets; gStaticSets = NULL; return; } if (gStaticSets == NULL) { status = U_MEMORY_ALLOCATION_ERROR; } } U_CDECL_END const DecimalFormatStaticSets *DecimalFormatStaticSets::getStaticSets(UErrorCode &status) { umtx_initOnce(gStaticSetsInitOnce, initSets, status); return gStaticSets; } const UnicodeSet *DecimalFormatStaticSets::getSimilarDecimals(UChar32 decimal, UBool strictParse) { UErrorCode status = U_ZERO_ERROR; umtx_initOnce(gStaticSetsInitOnce, initSets, status); if (U_FAILURE(status)) { return NULL; } if (gStaticSets->fDotEquivalents->contains(decimal)) { return strictParse ? gStaticSets->fStrictDotEquivalents : gStaticSets->fDotEquivalents; } if (gStaticSets->fCommaEquivalents->contains(decimal)) { return strictParse ? gStaticSets->fStrictCommaEquivalents : gStaticSets->fCommaEquivalents; } // if there is no match, return NULL return NULL; } U_NAMESPACE_END #endif // !UCONFIG_NO_FORMATTING