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