/src/icu/source/i18n/number_grouping.cpp
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | // © 2017 and later: Unicode, Inc. and others.  | 
2  |  | // License & terms of use: http://www.unicode.org/copyright.html  | 
3  |  |  | 
4  |  | #include "unicode/utypes.h"  | 
5  |  |  | 
6  |  | #if !UCONFIG_NO_FORMATTING  | 
7  |  |  | 
8  |  | #include "unicode/numberformatter.h"  | 
9  |  | #include "number_patternstring.h"  | 
10  |  | #include "uresimp.h"  | 
11  |  |  | 
12  |  | using namespace icu;  | 
13  |  | using namespace icu::number;  | 
14  |  | using namespace icu::number::impl;  | 
15  |  |  | 
16  |  | namespace { | 
17  |  |  | 
18  | 0  | int16_t getMinGroupingForLocale(const Locale& locale) { | 
19  |  |     // TODO: Cache this?  | 
20  | 0  |     UErrorCode localStatus = U_ZERO_ERROR;  | 
21  | 0  |     LocalUResourceBundlePointer bundle(ures_open(NULL, locale.getName(), &localStatus));  | 
22  | 0  |     int32_t resultLen = 0;  | 
23  | 0  |     const char16_t* result = ures_getStringByKeyWithFallback(  | 
24  | 0  |         bundle.getAlias(),  | 
25  | 0  |         "NumberElements/minimumGroupingDigits",  | 
26  | 0  |         &resultLen,  | 
27  | 0  |         &localStatus);  | 
28  |  |     // TODO: Is it safe to assume resultLen == 1? Would locales set minGrouping >= 10?  | 
29  | 0  |     if (U_FAILURE(localStatus) || resultLen != 1) { | 
30  | 0  |         return 1;  | 
31  | 0  |     }  | 
32  | 0  |     return result[0] - u'0';  | 
33  | 0  | }  | 
34  |  |  | 
35  |  | }  | 
36  |  |  | 
37  | 0  | Grouper Grouper::forStrategy(UNumberGroupingStrategy grouping) { | 
38  | 0  |     switch (grouping) { | 
39  | 0  |     case UNUM_GROUPING_OFF:  | 
40  | 0  |         return {-1, -1, -2, grouping}; | 
41  | 0  |     case UNUM_GROUPING_AUTO:  | 
42  | 0  |         return {-2, -2, -2, grouping}; | 
43  | 0  |     case UNUM_GROUPING_MIN2:  | 
44  | 0  |         return {-2, -2, -3, grouping}; | 
45  | 0  |     case UNUM_GROUPING_ON_ALIGNED:  | 
46  | 0  |         return {-4, -4, 1, grouping}; | 
47  | 0  |     case UNUM_GROUPING_THOUSANDS:  | 
48  | 0  |         return {3, 3, 1, grouping}; | 
49  | 0  |     default:  | 
50  | 0  |         UPRV_UNREACHABLE;  | 
51  | 0  |     }  | 
52  | 0  | }  | 
53  |  |  | 
54  | 0  | Grouper Grouper::forProperties(const DecimalFormatProperties& properties) { | 
55  | 0  |     if (!properties.groupingUsed) { | 
56  | 0  |         return forStrategy(UNUM_GROUPING_OFF);  | 
57  | 0  |     }  | 
58  | 0  |     auto grouping1 = static_cast<int16_t>(properties.groupingSize);  | 
59  | 0  |     auto grouping2 = static_cast<int16_t>(properties.secondaryGroupingSize);  | 
60  | 0  |     auto minGrouping = static_cast<int16_t>(properties.minimumGroupingDigits);  | 
61  | 0  |     grouping1 = grouping1 > 0 ? grouping1 : grouping2 > 0 ? grouping2 : grouping1;  | 
62  | 0  |     grouping2 = grouping2 > 0 ? grouping2 : grouping1;  | 
63  | 0  |     return {grouping1, grouping2, minGrouping, UNUM_GROUPING_COUNT}; | 
64  | 0  | }  | 
65  |  |  | 
66  | 0  | void Grouper::setLocaleData(const impl::ParsedPatternInfo &patternInfo, const Locale& locale) { | 
67  | 0  |     if (fMinGrouping == -2) { | 
68  | 0  |         fMinGrouping = getMinGroupingForLocale(locale);  | 
69  | 0  |     } else if (fMinGrouping == -3) { | 
70  | 0  |         fMinGrouping = static_cast<int16_t>(uprv_max(2, getMinGroupingForLocale(locale)));  | 
71  | 0  |     } else { | 
72  |  |         // leave fMinGrouping alone  | 
73  | 0  |     }  | 
74  | 0  |     if (fGrouping1 != -2 && fGrouping2 != -4) { | 
75  | 0  |         return;  | 
76  | 0  |     }  | 
77  | 0  |     auto grouping1 = static_cast<int16_t> (patternInfo.positive.groupingSizes & 0xffff);  | 
78  | 0  |     auto grouping2 = static_cast<int16_t> ((patternInfo.positive.groupingSizes >> 16) & 0xffff);  | 
79  | 0  |     auto grouping3 = static_cast<int16_t> ((patternInfo.positive.groupingSizes >> 32) & 0xffff);  | 
80  | 0  |     if (grouping2 == -1) { | 
81  | 0  |         grouping1 = fGrouping1 == -4 ? (short) 3 : (short) -1;  | 
82  | 0  |     }  | 
83  | 0  |     if (grouping3 == -1) { | 
84  | 0  |         grouping2 = grouping1;  | 
85  | 0  |     }  | 
86  | 0  |     fGrouping1 = grouping1;  | 
87  | 0  |     fGrouping2 = grouping2;  | 
88  | 0  | }  | 
89  |  |  | 
90  | 0  | bool Grouper::groupAtPosition(int32_t position, const impl::DecimalQuantity &value) const { | 
91  | 0  |     U_ASSERT(fGrouping1 > -2);  | 
92  | 0  |     if (fGrouping1 == -1 || fGrouping1 == 0) { | 
93  |  |         // Either -1 or 0 means "no grouping"  | 
94  | 0  |         return false;  | 
95  | 0  |     }  | 
96  | 0  |     position -= fGrouping1;  | 
97  | 0  |     return position >= 0 && (position % fGrouping2) == 0  | 
98  | 0  |            && value.getUpperDisplayMagnitude() - fGrouping1 + 1 >= fMinGrouping;  | 
99  | 0  | }  | 
100  |  |  | 
101  | 0  | int16_t Grouper::getPrimary() const { | 
102  | 0  |     return fGrouping1;  | 
103  | 0  | }  | 
104  |  |  | 
105  | 0  | int16_t Grouper::getSecondary() const { | 
106  | 0  |     return fGrouping2;  | 
107  | 0  | }  | 
108  |  |  | 
109  |  | #endif /* #if !UCONFIG_NO_FORMATTING */  |