1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
5 * Copyright (C) 2015, International Business Machines Corporation and *
6 * others. All Rights Reserved. *
7 *******************************************************************************
10 #include "numberformattesttuple.h"
12 #if !UCONFIG_NO_FORMATTING
20 static NumberFormatTestTuple *gNullPtr = NULL;
22 #define FIELD_OFFSET(fieldName) ((int32_t) (((char *) &gNullPtr->fieldName) - ((char *) gNullPtr)))
23 #define FIELD_FLAG_OFFSET(fieldName) ((int32_t) (((char *) &gNullPtr->fieldName##Flag) - ((char *) gNullPtr)))
25 #define FIELD_INIT(fieldName, fieldType) {#fieldName, FIELD_OFFSET(fieldName), FIELD_FLAG_OFFSET(fieldName), fieldType}
27 struct Numberformattesttuple_EnumConversion {
32 static Numberformattesttuple_EnumConversion gRoundingEnum[] = {
33 {"ceiling", DecimalFormat::kRoundCeiling},
34 {"floor", DecimalFormat::kRoundFloor},
35 {"down", DecimalFormat::kRoundDown},
36 {"up", DecimalFormat::kRoundUp},
37 {"halfEven", DecimalFormat::kRoundHalfEven},
38 {"halfDown", DecimalFormat::kRoundHalfDown},
39 {"halfUp", DecimalFormat::kRoundHalfUp},
40 {"unnecessary", DecimalFormat::kRoundUnnecessary}};
42 static Numberformattesttuple_EnumConversion gCurrencyUsageEnum[] = {
43 {"standard", UCURR_USAGE_STANDARD},
44 {"cash", UCURR_USAGE_CASH}};
46 static Numberformattesttuple_EnumConversion gPadPositionEnum[] = {
47 {"beforePrefix", DecimalFormat::kPadBeforePrefix},
48 {"afterPrefix", DecimalFormat::kPadAfterPrefix},
49 {"beforeSuffix", DecimalFormat::kPadBeforeSuffix},
50 {"afterSuffix", DecimalFormat::kPadAfterSuffix}};
52 static Numberformattesttuple_EnumConversion gFormatStyleEnum[] = {
53 {"patternDecimal", UNUM_PATTERN_DECIMAL},
54 {"decimal", UNUM_DECIMAL},
55 {"currency", UNUM_CURRENCY},
56 {"percent", UNUM_PERCENT},
57 {"scientific", UNUM_SCIENTIFIC},
58 {"spellout", UNUM_SPELLOUT},
59 {"ordinal", UNUM_ORDINAL},
60 {"duration", UNUM_DURATION},
61 {"numberingSystem", UNUM_NUMBERING_SYSTEM},
62 {"patternRuleBased", UNUM_PATTERN_RULEBASED},
63 {"currencyIso", UNUM_CURRENCY_ISO},
64 {"currencyPlural", UNUM_CURRENCY_PLURAL},
65 {"currencyAccounting", UNUM_CURRENCY_ACCOUNTING},
66 {"cashCurrency", UNUM_CASH_CURRENCY},
67 {"default", UNUM_DEFAULT},
68 {"ignore", UNUM_IGNORE}};
70 static int32_t toEnum(
71 const Numberformattesttuple_EnumConversion *table,
73 const UnicodeString &str,
75 if (U_FAILURE(status)) {
79 cstr.appendInvariantChars(str, status);
80 if (U_FAILURE(status)) {
83 for (int32_t i = 0; i < tableLength; ++i) {
84 if (uprv_strcmp(cstr.data(), table[i].str) == 0) {
85 return table[i].value;
88 status = U_ILLEGAL_ARGUMENT_ERROR;
93 const Numberformattesttuple_EnumConversion *table,
96 UnicodeString &appendTo) {
97 for (int32_t i = 0; i < tableLength; ++i) {
98 if (table[i].value == val) {
99 appendTo.append(table[i].str);
104 static void identVal(
105 const UnicodeString &str, void *strPtr, UErrorCode & /*status*/) {
106 *static_cast<UnicodeString *>(strPtr) = str;
109 static void identStr(
110 const void *strPtr, UnicodeString &appendTo) {
111 appendTo.append(*static_cast<const UnicodeString *>(strPtr));
114 static void strToLocale(
115 const UnicodeString &str, void *localePtr, UErrorCode &status) {
116 if (U_FAILURE(status)) {
119 CharString localeStr;
120 localeStr.appendInvariantChars(str, status);
121 *static_cast<Locale *>(localePtr) = Locale(localeStr.data());
124 static void localeToStr(
125 const void *localePtr, UnicodeString &appendTo) {
128 static_cast<const Locale *>(localePtr)->getName()));
131 static void strToInt(
132 const UnicodeString &str, void *intPtr, UErrorCode &status) {
133 if (U_FAILURE(status)) {
136 int32_t len = str.length();
139 if (len > 0 && str[0] == 0x2D) { // negative
144 status = U_ILLEGAL_ARGUMENT_ERROR;
148 for (int32_t i = start; i < len; ++i) {
150 if (ch < 0x30 || ch > 0x39) {
151 status = U_ILLEGAL_ARGUMENT_ERROR;
154 value = value * 10 - 0x30 + (int32_t) ch;
159 *static_cast<int32_t *>(intPtr) = value;
162 static void intToStr(
163 const void *intPtr, UnicodeString &appendTo) {
165 int32_t x = *static_cast<const int32_t *>(intPtr);
172 appendTo.append((UChar)0x2D);
174 int32_t len = uprv_itou(buffer, UPRV_LENGTHOF(buffer), (uint32_t) x, 10, 1);
175 appendTo.append(buffer, 0, len);
178 static void strToDouble(
179 const UnicodeString &str, void *doublePtr, UErrorCode &status) {
180 if (U_FAILURE(status)) {
184 buffer.appendInvariantChars(str, status);
185 if (U_FAILURE(status)) {
188 *static_cast<double *>(doublePtr) = atof(buffer.data());
191 static void doubleToStr(
192 const void *doublePtr, UnicodeString &appendTo) {
194 double x = *static_cast<const double *>(doublePtr);
195 sprintf(buffer, "%f", x);
196 appendTo.append(buffer);
199 static void strToERounding(
200 const UnicodeString &str, void *roundPtr, UErrorCode &status) {
201 int32_t val = toEnum(
202 gRoundingEnum, UPRV_LENGTHOF(gRoundingEnum), str, status);
203 *static_cast<DecimalFormat::ERoundingMode *>(roundPtr) = (DecimalFormat::ERoundingMode) val;
206 static void eRoundingToStr(
207 const void *roundPtr, UnicodeString &appendTo) {
208 DecimalFormat::ERoundingMode rounding =
209 *static_cast<const DecimalFormat::ERoundingMode *>(roundPtr);
212 UPRV_LENGTHOF(gRoundingEnum),
217 static void strToCurrencyUsage(
218 const UnicodeString &str, void *currencyUsagePtr, UErrorCode &status) {
219 int32_t val = toEnum(
220 gCurrencyUsageEnum, UPRV_LENGTHOF(gCurrencyUsageEnum), str, status);
221 *static_cast<UCurrencyUsage *>(currencyUsagePtr) = (UCurrencyUsage) val;
224 static void currencyUsageToStr(
225 const void *currencyUsagePtr, UnicodeString &appendTo) {
226 UCurrencyUsage currencyUsage =
227 *static_cast<const UCurrencyUsage *>(currencyUsagePtr);
230 UPRV_LENGTHOF(gCurrencyUsageEnum),
235 static void strToEPadPosition(
236 const UnicodeString &str, void *padPositionPtr, UErrorCode &status) {
237 int32_t val = toEnum(
238 gPadPositionEnum, UPRV_LENGTHOF(gPadPositionEnum), str, status);
239 *static_cast<DecimalFormat::EPadPosition *>(padPositionPtr) =
240 (DecimalFormat::EPadPosition) val;
243 static void ePadPositionToStr(
244 const void *padPositionPtr, UnicodeString &appendTo) {
245 DecimalFormat::EPadPosition padPosition =
246 *static_cast<const DecimalFormat::EPadPosition *>(padPositionPtr);
249 UPRV_LENGTHOF(gPadPositionEnum),
254 static void strToFormatStyle(
255 const UnicodeString &str, void *formatStylePtr, UErrorCode &status) {
256 int32_t val = toEnum(
257 gFormatStyleEnum, UPRV_LENGTHOF(gFormatStyleEnum), str, status);
258 *static_cast<UNumberFormatStyle *>(formatStylePtr) = (UNumberFormatStyle) val;
261 static void formatStyleToStr(
262 const void *formatStylePtr, UnicodeString &appendTo) {
263 UNumberFormatStyle formatStyle =
264 *static_cast<const UNumberFormatStyle *>(formatStylePtr);
267 UPRV_LENGTHOF(gFormatStyleEnum),
272 struct NumberFormatTestTupleFieldOps {
273 void (*toValue)(const UnicodeString &str, void *valPtr, UErrorCode &);
274 void (*toString)(const void *valPtr, UnicodeString &appendTo);
277 const NumberFormatTestTupleFieldOps gStrOps = {identVal, identStr};
278 const NumberFormatTestTupleFieldOps gIntOps = {strToInt, intToStr};
279 const NumberFormatTestTupleFieldOps gLocaleOps = {strToLocale, localeToStr};
280 const NumberFormatTestTupleFieldOps gDoubleOps = {strToDouble, doubleToStr};
281 const NumberFormatTestTupleFieldOps gERoundingOps = {strToERounding, eRoundingToStr};
282 const NumberFormatTestTupleFieldOps gCurrencyUsageOps = {strToCurrencyUsage, currencyUsageToStr};
283 const NumberFormatTestTupleFieldOps gEPadPositionOps = {strToEPadPosition, ePadPositionToStr};
284 const NumberFormatTestTupleFieldOps gFormatStyleOps = {strToFormatStyle, formatStyleToStr};
286 struct NumberFormatTestTupleFieldData {
290 const NumberFormatTestTupleFieldOps *ops;
293 // Order must correspond to ENumberFormatTestTupleField
294 const NumberFormatTestTupleFieldData gFieldData[] = {
295 FIELD_INIT(locale, &gLocaleOps),
296 FIELD_INIT(currency, &gStrOps),
297 FIELD_INIT(pattern, &gStrOps),
298 FIELD_INIT(format, &gStrOps),
299 FIELD_INIT(output, &gStrOps),
300 FIELD_INIT(comment, &gStrOps),
301 FIELD_INIT(minIntegerDigits, &gIntOps),
302 FIELD_INIT(maxIntegerDigits, &gIntOps),
303 FIELD_INIT(minFractionDigits, &gIntOps),
304 FIELD_INIT(maxFractionDigits, &gIntOps),
305 FIELD_INIT(minGroupingDigits, &gIntOps),
306 FIELD_INIT(breaks, &gStrOps),
307 FIELD_INIT(useSigDigits, &gIntOps),
308 FIELD_INIT(minSigDigits, &gIntOps),
309 FIELD_INIT(maxSigDigits, &gIntOps),
310 FIELD_INIT(useGrouping, &gIntOps),
311 FIELD_INIT(multiplier, &gIntOps),
312 FIELD_INIT(roundingIncrement, &gDoubleOps),
313 FIELD_INIT(formatWidth, &gIntOps),
314 FIELD_INIT(padCharacter, &gStrOps),
315 FIELD_INIT(useScientific, &gIntOps),
316 FIELD_INIT(grouping, &gIntOps),
317 FIELD_INIT(grouping2, &gIntOps),
318 FIELD_INIT(roundingMode, &gERoundingOps),
319 FIELD_INIT(currencyUsage, &gCurrencyUsageOps),
320 FIELD_INIT(minimumExponentDigits, &gIntOps),
321 FIELD_INIT(exponentSignAlwaysShown, &gIntOps),
322 FIELD_INIT(decimalSeparatorAlwaysShown, &gIntOps),
323 FIELD_INIT(padPosition, &gEPadPositionOps),
324 FIELD_INIT(positivePrefix, &gStrOps),
325 FIELD_INIT(positiveSuffix, &gStrOps),
326 FIELD_INIT(negativePrefix, &gStrOps),
327 FIELD_INIT(negativeSuffix, &gStrOps),
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(outputCurrency, &gStrOps)
342 NumberFormatTestTuple::setField(
343 ENumberFormatTestTupleField fieldId,
344 const UnicodeString &fieldValue,
345 UErrorCode &status) {
346 if (U_FAILURE(status)) {
349 if (fieldId == kNumberFormatTestTupleFieldCount) {
350 status = U_ILLEGAL_ARGUMENT_ERROR;
353 gFieldData[fieldId].ops->toValue(
354 fieldValue, getMutableFieldAddress(fieldId), status);
355 if (U_FAILURE(status)) {
358 setFlag(fieldId, TRUE);
363 NumberFormatTestTuple::clearField(
364 ENumberFormatTestTupleField fieldId,
365 UErrorCode &status) {
366 if (U_FAILURE(status)) {
369 if (fieldId == kNumberFormatTestTupleFieldCount) {
370 status = U_ILLEGAL_ARGUMENT_ERROR;
373 setFlag(fieldId, FALSE);
378 NumberFormatTestTuple::clear() {
379 for (int32_t i = 0; i < kNumberFormatTestTupleFieldCount; ++i) {
385 NumberFormatTestTuple::toString(
386 UnicodeString &appendTo) const {
387 appendTo.append("{");
389 for (int32_t i = 0; i < kNumberFormatTestTupleFieldCount; ++i) {
394 appendTo.append(", ");
397 appendTo.append(gFieldData[i].name);
398 appendTo.append(": ");
399 gFieldData[i].ops->toString(getFieldAddress(i), appendTo);
401 appendTo.append("}");
405 ENumberFormatTestTupleField
406 NumberFormatTestTuple::getFieldByName(
407 const UnicodeString &name) {
409 UErrorCode status = U_ZERO_ERROR;
410 buffer.appendInvariantChars(name, status);
411 if (U_FAILURE(status)) {
412 return kNumberFormatTestTupleFieldCount;
415 for (int32_t i = 0; i < UPRV_LENGTHOF(gFieldData); ++i) {
416 if (uprv_strcmp(gFieldData[i].name, buffer.data()) == 0) {
422 return kNumberFormatTestTupleFieldCount;
424 return (ENumberFormatTestTupleField) result;
428 NumberFormatTestTuple::getFieldAddress(int32_t fieldId) const {
429 return reinterpret_cast<const char *>(this) + gFieldData[fieldId].offset;
433 NumberFormatTestTuple::getMutableFieldAddress(int32_t fieldId) {
434 return reinterpret_cast<char *>(this) + gFieldData[fieldId].offset;
438 NumberFormatTestTuple::setFlag(int32_t fieldId, UBool value) {
439 void *flagAddr = reinterpret_cast<char *>(this) + gFieldData[fieldId].flagOffset;
440 *static_cast<UBool *>(flagAddr) = value;
444 NumberFormatTestTuple::isFlag(int32_t fieldId) const {
445 const void *flagAddr = reinterpret_cast<const char *>(this) + gFieldData[fieldId].flagOffset;
446 return *static_cast<const UBool *>(flagAddr);
449 #endif /* !UCONFIG_NO_FORMATTING */