Imported Upstream version 58.1
[platform/upstream/icu.git] / source / i18n / decfmtst.cpp
1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 *******************************************************************************
5 * Copyright (C) 2009-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 *******************************************************************************
8 *
9 * This file contains the class DecimalFormatStaticSets
10 *
11 * DecimalFormatStaticSets holds the UnicodeSets that are needed for lenient
12 * parsing of decimal and group separators.
13 ********************************************************************************
14 */
15
16 #include "unicode/utypes.h"
17
18 #if !UCONFIG_NO_FORMATTING
19
20 #include "unicode/unistr.h"
21 #include "unicode/uniset.h"
22 #include "unicode/uchar.h"
23 #include "cmemory.h"
24 #include "cstring.h"
25 #include "uassert.h"
26 #include "ucln_in.h"
27 #include "umutex.h"
28
29 #include "decfmtst.h"
30
31 U_NAMESPACE_BEGIN
32
33
34 //------------------------------------------------------------------------------
35 //
36 // Unicode Set pattern strings for all of the required constant sets.
37 //               Initialized with hex values for portability to EBCDIC based machines.
38 //                Really ugly, but there's no good way to avoid it.
39 //
40 //------------------------------------------------------------------------------
41
42 static const UChar gDotEquivalentsPattern[] = {
43         // [       .    \u2024  \u3002  \uFE12  \uFE52  \uFF0E  \uFF61     ]
44         0x005B, 0x002E, 0x2024, 0x3002, 0xFE12, 0xFE52, 0xFF0E, 0xFF61, 0x005D, 0x0000};
45
46 static const UChar gCommaEquivalentsPattern[] = {
47         // [       ,    \u060C  \u066B  \u3001  \uFE10  \uFE11  \uFE50  \uFE51  \uFF0C  \uFF64    ]
48         0x005B, 0x002C, 0x060C, 0x066B, 0x3001, 0xFE10, 0xFE11, 0xFE50, 0xFE51, 0xFF0C, 0xFF64, 0x005D, 0x0000};
49
50 static const UChar gOtherGroupingSeparatorsPattern[] = {
51         // [       \     SPACE     '      NBSP  \u066C  \u2000     -    \u200A  \u2018  \u2019  \u202F  \u205F  \u3000  \uFF07     ]
52         0x005B, 0x005C, 0x0020, 0x0027, 0x00A0, 0x066C, 0x2000, 0x002D, 0x200A, 0x2018, 0x2019, 0x202F, 0x205F, 0x3000, 0xFF07, 0x005D, 0x0000};
53
54 static const UChar gDashEquivalentsPattern[] = {
55         // [       \      -     HYPHEN  F_DASH  N_DASH   MINUS     ]
56         0x005B, 0x005C, 0x002D, 0x2010, 0x2012, 0x2013, 0x2212, 0x005D, 0x0000};
57
58 static const UChar gStrictDotEquivalentsPattern[] = {
59         // [      .     \u2024  \uFE52  \uFF0E  \uFF61    ]
60         0x005B, 0x002E, 0x2024, 0xFE52, 0xFF0E, 0xFF61, 0x005D, 0x0000};
61
62 static const UChar gStrictCommaEquivalentsPattern[] = {
63         // [       ,    \u066B  \uFE10  \uFE50  \uFF0C     ]
64         0x005B, 0x002C, 0x066B, 0xFE10, 0xFE50, 0xFF0C, 0x005D, 0x0000};
65
66 static const UChar gStrictOtherGroupingSeparatorsPattern[] = {
67         // [       \     SPACE     '      NBSP  \u066C  \u2000     -    \u200A  \u2018  \u2019  \u202F  \u205F  \u3000  \uFF07     ]
68         0x005B, 0x005C, 0x0020, 0x0027, 0x00A0, 0x066C, 0x2000, 0x002D, 0x200A, 0x2018, 0x2019, 0x202F, 0x205F, 0x3000, 0xFF07, 0x005D, 0x0000};
69
70 static const UChar gStrictDashEquivalentsPattern[] = {
71         // [       \      -      MINUS     ]
72         0x005B, 0x005C, 0x002D, 0x2212, 0x005D, 0x0000};
73
74 static UChar32 gMinusSigns[] = {
75     0x002D,
76     0x207B,
77     0x208B,
78     0x2212,
79     0x2796,
80     0xFE63,
81     0xFF0D};
82
83 static UChar32 gPlusSigns[] = {
84     0x002B,
85     0x207A,
86     0x208A,
87     0x2795,
88     0xfB29,
89     0xFE62,
90     0xFF0B};
91
92 static void initUnicodeSet(const UChar32 *raw, int32_t len, UnicodeSet *s) {
93     for (int32_t i = 0; i < len; ++i) {
94         s->add(raw[i]);
95     }
96 }
97
98 DecimalFormatStaticSets::DecimalFormatStaticSets(UErrorCode &status)
99 : fDotEquivalents(NULL),
100   fCommaEquivalents(NULL),
101   fOtherGroupingSeparators(NULL),
102   fDashEquivalents(NULL),
103   fStrictDotEquivalents(NULL),
104   fStrictCommaEquivalents(NULL),
105   fStrictOtherGroupingSeparators(NULL),
106   fStrictDashEquivalents(NULL),
107   fDefaultGroupingSeparators(NULL),
108   fStrictDefaultGroupingSeparators(NULL),
109   fMinusSigns(NULL),
110   fPlusSigns(NULL)
111 {
112     fDotEquivalents                = new UnicodeSet(UnicodeString(TRUE, gDotEquivalentsPattern, -1),                status);
113     fCommaEquivalents              = new UnicodeSet(UnicodeString(TRUE, gCommaEquivalentsPattern, -1),              status);
114     fOtherGroupingSeparators       = new UnicodeSet(UnicodeString(TRUE, gOtherGroupingSeparatorsPattern, -1),       status);
115     fDashEquivalents               = new UnicodeSet(UnicodeString(TRUE, gDashEquivalentsPattern, -1),               status);
116     
117     fStrictDotEquivalents          = new UnicodeSet(UnicodeString(TRUE, gStrictDotEquivalentsPattern, -1),          status);
118     fStrictCommaEquivalents        = new UnicodeSet(UnicodeString(TRUE, gStrictCommaEquivalentsPattern, -1),        status);
119     fStrictOtherGroupingSeparators = new UnicodeSet(UnicodeString(TRUE, gStrictOtherGroupingSeparatorsPattern, -1), status);
120     fStrictDashEquivalents         = new UnicodeSet(UnicodeString(TRUE, gStrictDashEquivalentsPattern, -1),         status);
121
122
123     fDefaultGroupingSeparators = new UnicodeSet(*fDotEquivalents);
124     fDefaultGroupingSeparators->addAll(*fCommaEquivalents);
125     fDefaultGroupingSeparators->addAll(*fOtherGroupingSeparators);
126
127     fStrictDefaultGroupingSeparators = new UnicodeSet(*fStrictDotEquivalents);
128     fStrictDefaultGroupingSeparators->addAll(*fStrictCommaEquivalents);
129     fStrictDefaultGroupingSeparators->addAll(*fStrictOtherGroupingSeparators);
130
131     fMinusSigns = new UnicodeSet();
132     fPlusSigns = new UnicodeSet();
133
134     // Check for null pointers
135     if (fDotEquivalents == NULL || fCommaEquivalents == NULL || fOtherGroupingSeparators == NULL || fDashEquivalents == NULL ||
136         fStrictDotEquivalents == NULL || fStrictCommaEquivalents == NULL || fStrictOtherGroupingSeparators == NULL || fStrictDashEquivalents == NULL ||
137         fDefaultGroupingSeparators == NULL || fStrictOtherGroupingSeparators == NULL ||
138         fMinusSigns == NULL || fPlusSigns == NULL) {
139       cleanup();
140       status = U_MEMORY_ALLOCATION_ERROR;
141       return;
142     }
143
144     initUnicodeSet(
145             gMinusSigns,
146             UPRV_LENGTHOF(gMinusSigns),
147             fMinusSigns);
148     initUnicodeSet(
149             gPlusSigns,
150             UPRV_LENGTHOF(gPlusSigns),
151             fPlusSigns);
152
153     // Freeze all the sets
154     fDotEquivalents->freeze();
155     fCommaEquivalents->freeze();
156     fOtherGroupingSeparators->freeze();
157     fDashEquivalents->freeze();
158     fStrictDotEquivalents->freeze();
159     fStrictCommaEquivalents->freeze();
160     fStrictOtherGroupingSeparators->freeze();
161     fStrictDashEquivalents->freeze();
162     fDefaultGroupingSeparators->freeze();
163     fStrictDefaultGroupingSeparators->freeze();
164     fMinusSigns->freeze();
165     fPlusSigns->freeze();
166 }
167
168 DecimalFormatStaticSets::~DecimalFormatStaticSets() {
169   cleanup();
170 }
171
172 void DecimalFormatStaticSets::cleanup() { // Be sure to clean up newly added fields!
173     delete fDotEquivalents; fDotEquivalents = NULL;
174     delete fCommaEquivalents; fCommaEquivalents = NULL;
175     delete fOtherGroupingSeparators; fOtherGroupingSeparators = NULL;
176     delete fDashEquivalents; fDashEquivalents = NULL;
177     delete fStrictDotEquivalents; fStrictDotEquivalents = NULL;
178     delete fStrictCommaEquivalents; fStrictCommaEquivalents = NULL;
179     delete fStrictOtherGroupingSeparators; fStrictOtherGroupingSeparators = NULL;
180     delete fStrictDashEquivalents; fStrictDashEquivalents = NULL;
181     delete fDefaultGroupingSeparators; fDefaultGroupingSeparators = NULL;
182     delete fStrictDefaultGroupingSeparators; fStrictDefaultGroupingSeparators = NULL;
183     delete fStrictOtherGroupingSeparators; fStrictOtherGroupingSeparators = NULL;
184     delete fMinusSigns; fMinusSigns = NULL;
185     delete fPlusSigns; fPlusSigns = NULL;
186 }
187
188 static DecimalFormatStaticSets *gStaticSets;
189 static icu::UInitOnce gStaticSetsInitOnce = U_INITONCE_INITIALIZER;
190
191
192 //------------------------------------------------------------------------------
193 //
194 //   decfmt_cleanup     Memory cleanup function, free/delete all
195 //                      cached memory.  Called by ICU's u_cleanup() function.
196 //
197 //------------------------------------------------------------------------------
198 U_CDECL_BEGIN
199 static UBool U_CALLCONV
200 decimfmt_cleanup(void)
201 {
202     delete gStaticSets;
203     gStaticSets = NULL;
204     gStaticSetsInitOnce.reset();
205     return TRUE;
206 }
207
208 static void U_CALLCONV initSets(UErrorCode &status) {
209     U_ASSERT(gStaticSets == NULL);
210     ucln_i18n_registerCleanup(UCLN_I18N_DECFMT, decimfmt_cleanup);
211     gStaticSets = new DecimalFormatStaticSets(status);
212     if (U_FAILURE(status)) {
213         delete gStaticSets;
214         gStaticSets = NULL;
215         return;
216     }
217     if (gStaticSets == NULL) {
218         status = U_MEMORY_ALLOCATION_ERROR;
219     }
220 }
221 U_CDECL_END
222
223 const DecimalFormatStaticSets *DecimalFormatStaticSets::getStaticSets(UErrorCode &status) {
224     umtx_initOnce(gStaticSetsInitOnce, initSets, status);
225     return gStaticSets;
226 }
227
228
229 const UnicodeSet *DecimalFormatStaticSets::getSimilarDecimals(UChar32 decimal, UBool strictParse)
230 {
231     UErrorCode status = U_ZERO_ERROR;
232     umtx_initOnce(gStaticSetsInitOnce, initSets, status);
233     if (U_FAILURE(status)) {
234         return NULL;
235     }
236
237     if (gStaticSets->fDotEquivalents->contains(decimal)) {
238         return strictParse ? gStaticSets->fStrictDotEquivalents : gStaticSets->fDotEquivalents;
239     }
240
241     if (gStaticSets->fCommaEquivalents->contains(decimal)) {
242         return strictParse ? gStaticSets->fStrictCommaEquivalents : gStaticSets->fCommaEquivalents;
243     }
244
245     // if there is no match, return NULL
246     return NULL;
247 }
248
249
250 U_NAMESPACE_END
251 #endif   // !UCONFIG_NO_FORMATTING