• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 *******************************************************************************
5 * Copyright (C) 2015, International Business Machines Corporation and         *
6 * others. All Rights Reserved.                                                *
7 *******************************************************************************
8 */
9 
10 #include "numberformattesttuple.h"
11 
12 #if !UCONFIG_NO_FORMATTING
13 
14 #include "ustrfmt.h"
15 #include "charstr.h"
16 #include "cstring.h"
17 #include "cmemory.h"
18 
19 static NumberFormatTestTuple emptyObject;
20 
21 static NumberFormatTestTuple *gNullPtr = &emptyObject;
22 
23 #define FIELD_OFFSET(fieldName) ((int32_t) (((char *) &gNullPtr->fieldName) - ((char *) gNullPtr)))
24 #define FIELD_FLAG_OFFSET(fieldName) ((int32_t) (((char *) &gNullPtr->fieldName##Flag) - ((char *) gNullPtr)))
25 
26 #define FIELD_INIT(fieldName, fieldType) {#fieldName, FIELD_OFFSET(fieldName), FIELD_FLAG_OFFSET(fieldName), fieldType}
27 
28 struct Numberformattesttuple_EnumConversion {
29     const char *str;
30     int32_t value;
31 };
32 
33 static Numberformattesttuple_EnumConversion gRoundingEnum[] = {
34     {"ceiling", DecimalFormat::kRoundCeiling},
35     {"floor", DecimalFormat::kRoundFloor},
36     {"down", DecimalFormat::kRoundDown},
37     {"up", DecimalFormat::kRoundUp},
38     {"halfEven", DecimalFormat::kRoundHalfEven},
39     {"halfDown", DecimalFormat::kRoundHalfDown},
40     {"halfUp", DecimalFormat::kRoundHalfUp},
41     {"unnecessary", DecimalFormat::kRoundUnnecessary}};
42 
43 static Numberformattesttuple_EnumConversion gCurrencyUsageEnum[] = {
44     {"standard", UCURR_USAGE_STANDARD},
45     {"cash", UCURR_USAGE_CASH}};
46 
47 static Numberformattesttuple_EnumConversion gPadPositionEnum[] = {
48     {"beforePrefix", DecimalFormat::kPadBeforePrefix},
49     {"afterPrefix", DecimalFormat::kPadAfterPrefix},
50     {"beforeSuffix", DecimalFormat::kPadBeforeSuffix},
51     {"afterSuffix", DecimalFormat::kPadAfterSuffix}};
52 
53 static Numberformattesttuple_EnumConversion gFormatStyleEnum[] = {
54     {"patternDecimal", UNUM_PATTERN_DECIMAL},
55     {"decimal", UNUM_DECIMAL},
56     {"currency", UNUM_CURRENCY},
57     {"percent", UNUM_PERCENT},
58     {"scientific", UNUM_SCIENTIFIC},
59     {"spellout", UNUM_SPELLOUT},
60     {"ordinal", UNUM_ORDINAL},
61     {"duration", UNUM_DURATION},
62     {"numberingSystem", UNUM_NUMBERING_SYSTEM},
63     {"patternRuleBased", UNUM_PATTERN_RULEBASED},
64     {"currencyIso", UNUM_CURRENCY_ISO},
65     {"currencyPlural", UNUM_CURRENCY_PLURAL},
66     {"currencyAccounting", UNUM_CURRENCY_ACCOUNTING},
67     {"cashCurrency", UNUM_CASH_CURRENCY},
68     {"default", UNUM_DEFAULT},
69     {"ignore", UNUM_IGNORE}};
70 
toEnum(const Numberformattesttuple_EnumConversion * table,int32_t tableLength,const UnicodeString & str,UErrorCode & status)71 static int32_t toEnum(
72         const Numberformattesttuple_EnumConversion *table,
73         int32_t tableLength,
74         const UnicodeString &str,
75         UErrorCode &status) {
76     if (U_FAILURE(status)) {
77         return 0;
78     }
79     CharString cstr;
80     cstr.appendInvariantChars(str, status);
81     if (U_FAILURE(status)) {
82         return 0;
83     }
84     for (int32_t i = 0; i < tableLength; ++i) {
85         if (uprv_strcmp(cstr.data(), table[i].str) == 0) {
86             return table[i].value;
87         }
88     }
89     status = U_ILLEGAL_ARGUMENT_ERROR;
90     return 0;
91 }
92 
fromEnum(const Numberformattesttuple_EnumConversion * table,int32_t tableLength,int32_t val,UnicodeString & appendTo)93 static void fromEnum(
94         const Numberformattesttuple_EnumConversion *table,
95         int32_t tableLength,
96         int32_t val,
97         UnicodeString &appendTo) {
98     for (int32_t i = 0; i < tableLength; ++i) {
99         if (table[i].value == val) {
100             appendTo.append(table[i].str);
101         }
102     }
103 }
104 
identVal(const UnicodeString & str,void * strPtr,UErrorCode &)105 static void identVal(
106         const UnicodeString &str, void *strPtr, UErrorCode & /*status*/) {
107     *static_cast<UnicodeString *>(strPtr) = str;
108 }
109 
identStr(const void * strPtr,UnicodeString & appendTo)110 static void identStr(
111         const void *strPtr, UnicodeString &appendTo) {
112     appendTo.append(*static_cast<const UnicodeString *>(strPtr));
113 }
114 
strToLocale(const UnicodeString & str,void * localePtr,UErrorCode & status)115 static void strToLocale(
116         const UnicodeString &str, void *localePtr, UErrorCode &status) {
117     if (U_FAILURE(status)) {
118         return;
119     }
120     CharString localeStr;
121     localeStr.appendInvariantChars(str, status);
122     *static_cast<Locale *>(localePtr) = Locale(localeStr.data());
123 }
124 
localeToStr(const void * localePtr,UnicodeString & appendTo)125 static void localeToStr(
126         const void *localePtr, UnicodeString &appendTo) {
127     appendTo.append(
128             UnicodeString(
129                     static_cast<const Locale *>(localePtr)->getName()));
130 }
131 
strToInt(const UnicodeString & str,void * intPtr,UErrorCode & status)132 static void strToInt(
133         const UnicodeString &str, void *intPtr, UErrorCode &status) {
134     if (U_FAILURE(status)) {
135         return;
136     }
137     int32_t len = str.length();
138     int32_t start = 0;
139     UBool neg = FALSE;
140     if (len > 0 && str[0] == 0x2D) { // negative
141         neg = TRUE;
142         start = 1;
143     }
144     if (start == len) {
145         status = U_ILLEGAL_ARGUMENT_ERROR;
146         return;
147     }
148     int64_t value = 0;
149     for (int32_t i = start; i < len; ++i) {
150         UChar ch = str[i];
151         if (ch < 0x30 || ch > 0x39) {
152             status = U_ILLEGAL_ARGUMENT_ERROR;
153             return;
154         }
155         value = value * 10 - 0x30 + (int32_t) ch;
156     }
157     int32_t signedValue = neg ? static_cast<int32_t>(-value) : static_cast<int32_t>(value);
158     *static_cast<int32_t *>(intPtr) = signedValue;
159 }
160 
intToStr(const void * intPtr,UnicodeString & appendTo)161 static void intToStr(
162         const void *intPtr, UnicodeString &appendTo) {
163     UChar buffer[20];
164     // int64_t such that all int32_t values can be negated
165     int64_t xSigned = *static_cast<const int32_t *>(intPtr);
166     uint32_t x;
167     if (xSigned < 0) {
168         appendTo.append((UChar)0x2D);
169         x = static_cast<uint32_t>(-xSigned);
170     } else {
171         x = static_cast<uint32_t>(xSigned);
172     }
173     int32_t len = uprv_itou(buffer, UPRV_LENGTHOF(buffer), x, 10, 1);
174     appendTo.append(buffer, 0, len);
175 }
176 
strToDouble(const UnicodeString & str,void * doublePtr,UErrorCode & status)177 static void strToDouble(
178         const UnicodeString &str, void *doublePtr, UErrorCode &status) {
179     if (U_FAILURE(status)) {
180         return;
181     }
182     CharString buffer;
183     buffer.appendInvariantChars(str, status);
184     if (U_FAILURE(status)) {
185         return;
186     }
187     *static_cast<double *>(doublePtr) = atof(buffer.data());
188 }
189 
doubleToStr(const void * doublePtr,UnicodeString & appendTo)190 static void doubleToStr(
191         const void *doublePtr, UnicodeString &appendTo) {
192     char buffer[256];
193     double x = *static_cast<const double *>(doublePtr);
194     sprintf(buffer, "%f", x);
195     appendTo.append(buffer);
196 }
197 
strToERounding(const UnicodeString & str,void * roundPtr,UErrorCode & status)198 static void strToERounding(
199         const UnicodeString &str, void *roundPtr, UErrorCode &status) {
200     int32_t val = toEnum(
201             gRoundingEnum, UPRV_LENGTHOF(gRoundingEnum), str, status);
202     *static_cast<DecimalFormat::ERoundingMode *>(roundPtr) = (DecimalFormat::ERoundingMode) val;
203 }
204 
eRoundingToStr(const void * roundPtr,UnicodeString & appendTo)205 static void eRoundingToStr(
206         const void *roundPtr, UnicodeString &appendTo) {
207     DecimalFormat::ERoundingMode rounding =
208             *static_cast<const DecimalFormat::ERoundingMode *>(roundPtr);
209     fromEnum(
210             gRoundingEnum,
211             UPRV_LENGTHOF(gRoundingEnum),
212             rounding,
213             appendTo);
214 }
215 
strToCurrencyUsage(const UnicodeString & str,void * currencyUsagePtr,UErrorCode & status)216 static void strToCurrencyUsage(
217         const UnicodeString &str, void *currencyUsagePtr, UErrorCode &status) {
218     int32_t val = toEnum(
219             gCurrencyUsageEnum, UPRV_LENGTHOF(gCurrencyUsageEnum), str, status);
220     *static_cast<UCurrencyUsage *>(currencyUsagePtr) = (UCurrencyUsage) val;
221 }
222 
currencyUsageToStr(const void * currencyUsagePtr,UnicodeString & appendTo)223 static void currencyUsageToStr(
224         const void *currencyUsagePtr, UnicodeString &appendTo) {
225     UCurrencyUsage currencyUsage =
226             *static_cast<const UCurrencyUsage *>(currencyUsagePtr);
227     fromEnum(
228             gCurrencyUsageEnum,
229             UPRV_LENGTHOF(gCurrencyUsageEnum),
230             currencyUsage,
231             appendTo);
232 }
233 
strToEPadPosition(const UnicodeString & str,void * padPositionPtr,UErrorCode & status)234 static void strToEPadPosition(
235         const UnicodeString &str, void *padPositionPtr, UErrorCode &status) {
236     int32_t val = toEnum(
237             gPadPositionEnum, UPRV_LENGTHOF(gPadPositionEnum), str, status);
238     *static_cast<DecimalFormat::EPadPosition *>(padPositionPtr) =
239             (DecimalFormat::EPadPosition) val;
240 }
241 
ePadPositionToStr(const void * padPositionPtr,UnicodeString & appendTo)242 static void ePadPositionToStr(
243         const void *padPositionPtr, UnicodeString &appendTo) {
244     DecimalFormat::EPadPosition padPosition =
245             *static_cast<const DecimalFormat::EPadPosition *>(padPositionPtr);
246     fromEnum(
247             gPadPositionEnum,
248             UPRV_LENGTHOF(gPadPositionEnum),
249             padPosition,
250             appendTo);
251 }
252 
strToFormatStyle(const UnicodeString & str,void * formatStylePtr,UErrorCode & status)253 static void strToFormatStyle(
254         const UnicodeString &str, void *formatStylePtr, UErrorCode &status) {
255     int32_t val = toEnum(
256             gFormatStyleEnum, UPRV_LENGTHOF(gFormatStyleEnum), str, status);
257     *static_cast<UNumberFormatStyle *>(formatStylePtr) = (UNumberFormatStyle) val;
258 }
259 
formatStyleToStr(const void * formatStylePtr,UnicodeString & appendTo)260 static void formatStyleToStr(
261         const void *formatStylePtr, UnicodeString &appendTo) {
262     UNumberFormatStyle formatStyle =
263             *static_cast<const UNumberFormatStyle *>(formatStylePtr);
264     fromEnum(
265             gFormatStyleEnum,
266             UPRV_LENGTHOF(gFormatStyleEnum),
267             formatStyle,
268             appendTo);
269 }
270 
271 struct NumberFormatTestTupleFieldOps {
272     void (*toValue)(const UnicodeString &str, void *valPtr, UErrorCode &);
273     void (*toString)(const void *valPtr, UnicodeString &appendTo);
274 };
275 
276 const NumberFormatTestTupleFieldOps gStrOps = {identVal, identStr};
277 const NumberFormatTestTupleFieldOps gIntOps = {strToInt, intToStr};
278 const NumberFormatTestTupleFieldOps gLocaleOps = {strToLocale, localeToStr};
279 const NumberFormatTestTupleFieldOps gDoubleOps = {strToDouble, doubleToStr};
280 const NumberFormatTestTupleFieldOps gERoundingOps = {strToERounding, eRoundingToStr};
281 const NumberFormatTestTupleFieldOps gCurrencyUsageOps = {strToCurrencyUsage, currencyUsageToStr};
282 const NumberFormatTestTupleFieldOps gEPadPositionOps = {strToEPadPosition, ePadPositionToStr};
283 const NumberFormatTestTupleFieldOps gFormatStyleOps = {strToFormatStyle, formatStyleToStr};
284 
285 struct NumberFormatTestTupleFieldData {
286     const char *name;
287     int32_t offset;
288     int32_t flagOffset;
289     const NumberFormatTestTupleFieldOps *ops;
290 };
291 
292 // Order must correspond to ENumberFormatTestTupleField
293 const NumberFormatTestTupleFieldData gFieldData[] = {
294     FIELD_INIT(locale, &gLocaleOps),
295     FIELD_INIT(currency, &gStrOps),
296     FIELD_INIT(pattern, &gStrOps),
297     FIELD_INIT(format, &gStrOps),
298     FIELD_INIT(output, &gStrOps),
299     FIELD_INIT(comment, &gStrOps),
300     FIELD_INIT(minIntegerDigits, &gIntOps),
301     FIELD_INIT(maxIntegerDigits, &gIntOps),
302     FIELD_INIT(minFractionDigits, &gIntOps),
303     FIELD_INIT(maxFractionDigits, &gIntOps),
304     FIELD_INIT(minGroupingDigits, &gIntOps),
305     FIELD_INIT(breaks, &gStrOps),
306     FIELD_INIT(useSigDigits, &gIntOps),
307     FIELD_INIT(minSigDigits, &gIntOps),
308     FIELD_INIT(maxSigDigits, &gIntOps),
309     FIELD_INIT(useGrouping, &gIntOps),
310     FIELD_INIT(multiplier, &gIntOps),
311     FIELD_INIT(roundingIncrement, &gDoubleOps),
312     FIELD_INIT(formatWidth, &gIntOps),
313     FIELD_INIT(padCharacter, &gStrOps),
314     FIELD_INIT(useScientific, &gIntOps),
315     FIELD_INIT(grouping, &gIntOps),
316     FIELD_INIT(grouping2, &gIntOps),
317     FIELD_INIT(roundingMode, &gERoundingOps),
318     FIELD_INIT(currencyUsage, &gCurrencyUsageOps),
319     FIELD_INIT(minimumExponentDigits, &gIntOps),
320     FIELD_INIT(exponentSignAlwaysShown, &gIntOps),
321     FIELD_INIT(decimalSeparatorAlwaysShown, &gIntOps),
322     FIELD_INIT(padPosition, &gEPadPositionOps),
323     FIELD_INIT(positivePrefix, &gStrOps),
324     FIELD_INIT(positiveSuffix, &gStrOps),
325     FIELD_INIT(negativePrefix, &gStrOps),
326     FIELD_INIT(negativeSuffix, &gStrOps),
327     FIELD_INIT(signAlwaysShown, &gIntOps),
328     FIELD_INIT(localizedPattern, &gStrOps),
329     FIELD_INIT(toPattern, &gStrOps),
330     FIELD_INIT(toLocalizedPattern, &gStrOps),
331     FIELD_INIT(style, &gFormatStyleOps),
332     FIELD_INIT(parse, &gStrOps),
333     FIELD_INIT(lenient, &gIntOps),
334     FIELD_INIT(plural, &gStrOps),
335     FIELD_INIT(parseIntegerOnly, &gIntOps),
336     FIELD_INIT(decimalPatternMatchRequired, &gIntOps),
337     FIELD_INIT(parseNoExponent, &gIntOps),
338     FIELD_INIT(parseCaseSensitive, &gIntOps),
339     FIELD_INIT(outputCurrency, &gStrOps)
340 };
341 
342 UBool
setField(ENumberFormatTestTupleField fieldId,const UnicodeString & fieldValue,UErrorCode & status)343 NumberFormatTestTuple::setField(
344         ENumberFormatTestTupleField fieldId,
345         const UnicodeString &fieldValue,
346         UErrorCode &status) {
347     if (U_FAILURE(status)) {
348         return FALSE;
349     }
350     if (fieldId == kNumberFormatTestTupleFieldCount) {
351         status = U_ILLEGAL_ARGUMENT_ERROR;
352         return FALSE;
353     }
354     gFieldData[fieldId].ops->toValue(
355             fieldValue, getMutableFieldAddress(fieldId), status);
356     if (U_FAILURE(status)) {
357         return FALSE;
358     }
359     setFlag(fieldId, TRUE);
360     return TRUE;
361 }
362 
363 UBool
clearField(ENumberFormatTestTupleField fieldId,UErrorCode & status)364 NumberFormatTestTuple::clearField(
365         ENumberFormatTestTupleField fieldId,
366         UErrorCode &status) {
367     if (U_FAILURE(status)) {
368         return FALSE;
369     }
370     if (fieldId == kNumberFormatTestTupleFieldCount) {
371         status = U_ILLEGAL_ARGUMENT_ERROR;
372         return FALSE;
373     }
374     setFlag(fieldId, FALSE);
375     return TRUE;
376 }
377 
378 void
clear()379 NumberFormatTestTuple::clear() {
380     for (int32_t i = 0; i < kNumberFormatTestTupleFieldCount; ++i) {
381         setFlag(i, FALSE);
382     }
383 }
384 
385 UnicodeString &
toString(UnicodeString & appendTo) const386 NumberFormatTestTuple::toString(
387         UnicodeString &appendTo) const {
388     appendTo.append("{");
389     UBool first = TRUE;
390     for (int32_t i = 0; i < kNumberFormatTestTupleFieldCount; ++i) {
391         if (!isFlag(i)) {
392             continue;
393         }
394         if (!first) {
395             appendTo.append(", ");
396         }
397         first = FALSE;
398         appendTo.append(gFieldData[i].name);
399         appendTo.append(": ");
400         gFieldData[i].ops->toString(getFieldAddress(i), appendTo);
401     }
402     appendTo.append("}");
403     return appendTo;
404 }
405 
406 ENumberFormatTestTupleField
getFieldByName(const UnicodeString & name)407 NumberFormatTestTuple::getFieldByName(
408         const UnicodeString &name) {
409     CharString buffer;
410     UErrorCode status = U_ZERO_ERROR;
411     buffer.appendInvariantChars(name, status);
412     if (U_FAILURE(status)) {
413         return kNumberFormatTestTupleFieldCount;
414     }
415     int32_t result = -1;
416     for (int32_t i = 0; i < UPRV_LENGTHOF(gFieldData); ++i) {
417         if (uprv_strcmp(gFieldData[i].name, buffer.data()) == 0) {
418             result = i;
419             break;
420         }
421     }
422     if (result == -1) {
423         return kNumberFormatTestTupleFieldCount;
424     }
425     return (ENumberFormatTestTupleField) result;
426 }
427 
428 const void *
getFieldAddress(int32_t fieldId) const429 NumberFormatTestTuple::getFieldAddress(int32_t fieldId) const {
430     return reinterpret_cast<const char *>(this) + gFieldData[fieldId].offset;
431 }
432 
433 void *
getMutableFieldAddress(int32_t fieldId)434 NumberFormatTestTuple::getMutableFieldAddress(int32_t fieldId) {
435     return reinterpret_cast<char *>(this) + gFieldData[fieldId].offset;
436 }
437 
438 void
setFlag(int32_t fieldId,UBool value)439 NumberFormatTestTuple::setFlag(int32_t fieldId, UBool value) {
440     void *flagAddr = reinterpret_cast<char *>(this) + gFieldData[fieldId].flagOffset;
441     *static_cast<UBool *>(flagAddr) = value;
442 }
443 
444 UBool
isFlag(int32_t fieldId) const445 NumberFormatTestTuple::isFlag(int32_t fieldId) const {
446     const void *flagAddr = reinterpret_cast<const char *>(this) + gFieldData[fieldId].flagOffset;
447     return *static_cast<const UBool *>(flagAddr);
448 }
449 
450 #endif /* !UCONFIG_NO_FORMATTING */
451