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