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