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