]>
Commit | Line | Data |
---|---|---|
f3c0d7a5 A |
1 | // © 2016 and later: Unicode, Inc. and others. |
2 | // License & terms of use: http://www.unicode.org/copyright.html | |
b75a7d8f A |
3 | /* |
4 | ******************************************************************************* | |
2ca993e8 A |
5 | * Copyright (C) 1997-2016, International Business Machines Corporation and |
6 | * others. All Rights Reserved. | |
b75a7d8f A |
7 | ******************************************************************************* |
8 | * | |
9 | * File FMTABLE.CPP | |
10 | * | |
11 | * Modification History: | |
12 | * | |
13 | * Date Name Description | |
14 | * 03/25/97 clhuang Initial Implementation. | |
15 | ******************************************************************************** | |
16 | */ | |
17 | ||
18 | #include "unicode/utypes.h" | |
19 | ||
20 | #if !UCONFIG_NO_FORMATTING | |
21 | ||
729e4ab9 | 22 | #include <math.h> |
b75a7d8f | 23 | #include "unicode/fmtable.h" |
374ca955 A |
24 | #include "unicode/ustring.h" |
25 | #include "unicode/measure.h" | |
26 | #include "unicode/curramt.h" | |
57a6839d | 27 | #include "unicode/uformattable.h" |
729e4ab9 | 28 | #include "charstr.h" |
b75a7d8f | 29 | #include "cmemory.h" |
729e4ab9 A |
30 | #include "cstring.h" |
31 | #include "decNumber.h" | |
32 | #include "digitlst.h" | |
b331163b | 33 | #include "fmtableimp.h" |
0f5d89e8 | 34 | #include "number_decimalquantity.h" |
b75a7d8f A |
35 | |
36 | // ***************************************************************************** | |
37 | // class Formattable | |
38 | // ***************************************************************************** | |
39 | ||
40 | U_NAMESPACE_BEGIN | |
41 | ||
374ca955 A |
42 | UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Formattable) |
43 | ||
0f5d89e8 A |
44 | using number::impl::DecimalQuantity; |
45 | ||
51004dcb | 46 | |
374ca955 A |
47 | //-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. |
48 | ||
49 | // NOTE: As of 3.0, there are limitations to the UObject API. It does | |
729e4ab9 | 50 | // not (yet) support cloning, operator=, nor operator==. To |
374ca955 A |
51 | // work around this, I implement some simple inlines here. Later |
52 | // these can be modified or removed. [alan] | |
53 | ||
54 | // NOTE: These inlines assume that all fObjects are in fact instances | |
55 | // of the Measure class, which is true as of 3.0. [alan] | |
56 | ||
57 | // Return TRUE if *a == *b. | |
73c04bcf | 58 | static inline UBool objectEquals(const UObject* a, const UObject* b) { |
374ca955 A |
59 | // LATER: return *a == *b; |
60 | return *((const Measure*) a) == *((const Measure*) b); | |
61 | } | |
62 | ||
63 | // Return a clone of *a. | |
73c04bcf | 64 | static inline UObject* objectClone(const UObject* a) { |
374ca955 A |
65 | // LATER: return a->clone(); |
66 | return ((const Measure*) a)->clone(); | |
67 | } | |
68 | ||
69 | // Return TRUE if *a is an instance of Measure. | |
73c04bcf | 70 | static inline UBool instanceOfMeasure(const UObject* a) { |
729e4ab9 | 71 | return dynamic_cast<const Measure*>(a) != NULL; |
374ca955 A |
72 | } |
73 | ||
73c04bcf A |
74 | /** |
75 | * Creates a new Formattable array and copies the values from the specified | |
76 | * original. | |
77 | * @param array the original array | |
78 | * @param count the original array count | |
79 | * @return the new Formattable array. | |
80 | */ | |
729e4ab9 | 81 | static Formattable* createArrayCopy(const Formattable* array, int32_t count) { |
73c04bcf | 82 | Formattable *result = new Formattable[count]; |
46f4442e A |
83 | if (result != NULL) { |
84 | for (int32_t i=0; i<count; ++i) | |
85 | result[i] = array[i]; // Don't memcpy! | |
86 | } | |
73c04bcf A |
87 | return result; |
88 | } | |
89 | ||
374ca955 A |
90 | //-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. |
91 | ||
92 | /** | |
93 | * Set 'ec' to 'err' only if 'ec' is not already set to a failing UErrorCode. | |
94 | */ | |
729e4ab9 | 95 | static void setError(UErrorCode& ec, UErrorCode err) { |
374ca955 A |
96 | if (U_SUCCESS(ec)) { |
97 | ec = err; | |
98 | } | |
99 | } | |
b75a7d8f | 100 | |
729e4ab9 A |
101 | // |
102 | // Common initialization code, shared by constructors. | |
103 | // Put everything into a known state. | |
104 | // | |
105 | void Formattable::init() { | |
106 | fValue.fInt64 = 0; | |
107 | fType = kLong; | |
108 | fDecimalStr = NULL; | |
109 | fDecimalNum = NULL; | |
0f5d89e8 | 110 | fDecimalQuantity = NULL; |
729e4ab9 A |
111 | fBogus.setToBogus(); |
112 | } | |
113 | ||
b75a7d8f A |
114 | // ------------------------------------- |
115 | // default constructor. | |
116 | // Creates a formattable object with a long value 0. | |
117 | ||
729e4ab9 A |
118 | Formattable::Formattable() { |
119 | init(); | |
b75a7d8f A |
120 | } |
121 | ||
122 | // ------------------------------------- | |
123 | // Creates a formattable object with a Date instance. | |
124 | ||
125 | Formattable::Formattable(UDate date, ISDATE /*isDate*/) | |
b75a7d8f | 126 | { |
729e4ab9 A |
127 | init(); |
128 | fType = kDate; | |
b75a7d8f A |
129 | fValue.fDate = date; |
130 | } | |
131 | ||
132 | // ------------------------------------- | |
133 | // Creates a formattable object with a double value. | |
134 | ||
135 | Formattable::Formattable(double value) | |
b75a7d8f | 136 | { |
729e4ab9 A |
137 | init(); |
138 | fType = kDouble; | |
b75a7d8f A |
139 | fValue.fDouble = value; |
140 | } | |
141 | ||
142 | // ------------------------------------- | |
729e4ab9 | 143 | // Creates a formattable object with an int32_t value. |
b75a7d8f A |
144 | |
145 | Formattable::Formattable(int32_t value) | |
b75a7d8f | 146 | { |
729e4ab9 | 147 | init(); |
374ca955 A |
148 | fValue.fInt64 = value; |
149 | } | |
150 | ||
151 | // ------------------------------------- | |
729e4ab9 | 152 | // Creates a formattable object with an int64_t value. |
374ca955 A |
153 | |
154 | Formattable::Formattable(int64_t value) | |
374ca955 | 155 | { |
729e4ab9 A |
156 | init(); |
157 | fType = kInt64; | |
374ca955 | 158 | fValue.fInt64 = value; |
b75a7d8f A |
159 | } |
160 | ||
729e4ab9 A |
161 | // ------------------------------------- |
162 | // Creates a formattable object with a decimal number value from a string. | |
163 | ||
f3c0d7a5 | 164 | Formattable::Formattable(StringPiece number, UErrorCode &status) { |
729e4ab9 A |
165 | init(); |
166 | setDecimalNumber(number, status); | |
167 | } | |
168 | ||
169 | ||
b75a7d8f A |
170 | // ------------------------------------- |
171 | // Creates a formattable object with a UnicodeString instance. | |
172 | ||
173 | Formattable::Formattable(const UnicodeString& stringToCopy) | |
b75a7d8f | 174 | { |
729e4ab9 A |
175 | init(); |
176 | fType = kString; | |
b75a7d8f A |
177 | fValue.fString = new UnicodeString(stringToCopy); |
178 | } | |
179 | ||
180 | // ------------------------------------- | |
181 | // Creates a formattable object with a UnicodeString* value. | |
182 | // (adopting symantics) | |
183 | ||
184 | Formattable::Formattable(UnicodeString* stringToAdopt) | |
b75a7d8f | 185 | { |
729e4ab9 A |
186 | init(); |
187 | fType = kString; | |
b75a7d8f A |
188 | fValue.fString = stringToAdopt; |
189 | } | |
190 | ||
374ca955 | 191 | Formattable::Formattable(UObject* objectToAdopt) |
374ca955 | 192 | { |
729e4ab9 A |
193 | init(); |
194 | fType = kObject; | |
374ca955 A |
195 | fValue.fObject = objectToAdopt; |
196 | } | |
197 | ||
b75a7d8f A |
198 | // ------------------------------------- |
199 | ||
200 | Formattable::Formattable(const Formattable* arrayToCopy, int32_t count) | |
201 | : UObject(), fType(kArray) | |
202 | { | |
729e4ab9 A |
203 | init(); |
204 | fType = kArray; | |
b75a7d8f A |
205 | fValue.fArrayAndCount.fArray = createArrayCopy(arrayToCopy, count); |
206 | fValue.fArrayAndCount.fCount = count; | |
207 | } | |
208 | ||
209 | // ------------------------------------- | |
210 | // copy constructor | |
211 | ||
729e4ab9 | 212 | |
b75a7d8f | 213 | Formattable::Formattable(const Formattable &source) |
729e4ab9 | 214 | : UObject(*this) |
b75a7d8f | 215 | { |
729e4ab9 | 216 | init(); |
b75a7d8f A |
217 | *this = source; |
218 | } | |
219 | ||
220 | // ------------------------------------- | |
221 | // assignment operator | |
222 | ||
223 | Formattable& | |
224 | Formattable::operator=(const Formattable& source) | |
225 | { | |
226 | if (this != &source) | |
227 | { | |
228 | // Disposes the current formattable value/setting. | |
229 | dispose(); | |
230 | ||
231 | // Sets the correct data type for this value. | |
232 | fType = source.fType; | |
233 | switch (fType) | |
234 | { | |
235 | case kArray: | |
236 | // Sets each element in the array one by one and records the array count. | |
237 | fValue.fArrayAndCount.fCount = source.fValue.fArrayAndCount.fCount; | |
238 | fValue.fArrayAndCount.fArray = createArrayCopy(source.fValue.fArrayAndCount.fArray, | |
239 | source.fValue.fArrayAndCount.fCount); | |
240 | break; | |
241 | case kString: | |
242 | // Sets the string value. | |
243 | fValue.fString = new UnicodeString(*source.fValue.fString); | |
244 | break; | |
245 | case kDouble: | |
246 | // Sets the double value. | |
247 | fValue.fDouble = source.fValue.fDouble; | |
248 | break; | |
249 | case kLong: | |
374ca955 | 250 | case kInt64: |
b75a7d8f | 251 | // Sets the long value. |
374ca955 | 252 | fValue.fInt64 = source.fValue.fInt64; |
b75a7d8f A |
253 | break; |
254 | case kDate: | |
255 | // Sets the Date value. | |
256 | fValue.fDate = source.fValue.fDate; | |
257 | break; | |
374ca955 A |
258 | case kObject: |
259 | fValue.fObject = objectClone(source.fValue.fObject); | |
260 | break; | |
b75a7d8f | 261 | } |
729e4ab9 A |
262 | |
263 | UErrorCode status = U_ZERO_ERROR; | |
264 | if (source.fDecimalNum != NULL) { | |
51004dcb | 265 | fDecimalNum = new DigitList(*source.fDecimalNum); // TODO: use internal digit list |
729e4ab9 | 266 | } |
0f5d89e8 A |
267 | if (source.fDecimalQuantity != NULL) { |
268 | fDecimalQuantity = new DecimalQuantity(*source.fDecimalQuantity); | |
269 | } | |
729e4ab9 A |
270 | if (source.fDecimalStr != NULL) { |
271 | fDecimalStr = new CharString(*source.fDecimalStr, status); | |
272 | if (U_FAILURE(status)) { | |
273 | delete fDecimalStr; | |
274 | fDecimalStr = NULL; | |
275 | } | |
276 | } | |
b75a7d8f A |
277 | } |
278 | return *this; | |
279 | } | |
280 | ||
281 | // ------------------------------------- | |
282 | ||
283 | UBool | |
284 | Formattable::operator==(const Formattable& that) const | |
285 | { | |
374ca955 A |
286 | int32_t i; |
287 | ||
b75a7d8f A |
288 | if (this == &that) return TRUE; |
289 | ||
290 | // Returns FALSE if the data types are different. | |
291 | if (fType != that.fType) return FALSE; | |
292 | ||
293 | // Compares the actual data values. | |
374ca955 | 294 | UBool equal = TRUE; |
b75a7d8f A |
295 | switch (fType) { |
296 | case kDate: | |
374ca955 A |
297 | equal = (fValue.fDate == that.fValue.fDate); |
298 | break; | |
b75a7d8f | 299 | case kDouble: |
374ca955 A |
300 | equal = (fValue.fDouble == that.fValue.fDouble); |
301 | break; | |
b75a7d8f | 302 | case kLong: |
374ca955 A |
303 | case kInt64: |
304 | equal = (fValue.fInt64 == that.fValue.fInt64); | |
305 | break; | |
b75a7d8f | 306 | case kString: |
374ca955 A |
307 | equal = (*(fValue.fString) == *(that.fValue.fString)); |
308 | break; | |
b75a7d8f | 309 | case kArray: |
374ca955 A |
310 | if (fValue.fArrayAndCount.fCount != that.fValue.fArrayAndCount.fCount) { |
311 | equal = FALSE; | |
312 | break; | |
313 | } | |
b75a7d8f | 314 | // Checks each element for equality. |
374ca955 A |
315 | for (i=0; i<fValue.fArrayAndCount.fCount; ++i) { |
316 | if (fValue.fArrayAndCount.fArray[i] != that.fValue.fArrayAndCount.fArray[i]) { | |
317 | equal = FALSE; | |
318 | break; | |
319 | } | |
320 | } | |
321 | break; | |
322 | case kObject: | |
46f4442e A |
323 | if (fValue.fObject == NULL || that.fValue.fObject == NULL) { |
324 | equal = FALSE; | |
325 | } else { | |
326 | equal = objectEquals(fValue.fObject, that.fValue.fObject); | |
327 | } | |
b75a7d8f A |
328 | break; |
329 | } | |
374ca955 | 330 | |
729e4ab9 | 331 | // TODO: compare digit lists if numeric. |
374ca955 | 332 | return equal; |
b75a7d8f A |
333 | } |
334 | ||
335 | // ------------------------------------- | |
336 | ||
337 | Formattable::~Formattable() | |
338 | { | |
339 | dispose(); | |
340 | } | |
341 | ||
342 | // ------------------------------------- | |
343 | ||
344 | void Formattable::dispose() | |
345 | { | |
346 | // Deletes the data value if necessary. | |
347 | switch (fType) { | |
348 | case kString: | |
349 | delete fValue.fString; | |
350 | break; | |
351 | case kArray: | |
352 | delete[] fValue.fArrayAndCount.fArray; | |
353 | break; | |
374ca955 A |
354 | case kObject: |
355 | delete fValue.fObject; | |
356 | break; | |
357 | default: | |
b75a7d8f A |
358 | break; |
359 | } | |
729e4ab9 A |
360 | |
361 | fType = kLong; | |
362 | fValue.fInt64 = 0; | |
51004dcb | 363 | |
729e4ab9 A |
364 | delete fDecimalStr; |
365 | fDecimalStr = NULL; | |
51004dcb A |
366 | |
367 | FmtStackData *stackData = (FmtStackData*)fStackData; | |
368 | if(fDecimalNum != &(stackData->stackDecimalNum)) { | |
369 | delete fDecimalNum; | |
370 | } else { | |
371 | fDecimalNum->~DigitList(); // destruct, don't deallocate | |
372 | } | |
729e4ab9 | 373 | fDecimalNum = NULL; |
0f5d89e8 A |
374 | |
375 | delete fDecimalQuantity; | |
376 | fDecimalQuantity = NULL; | |
b75a7d8f A |
377 | } |
378 | ||
374ca955 A |
379 | Formattable * |
380 | Formattable::clone() const { | |
381 | return new Formattable(*this); | |
382 | } | |
383 | ||
b75a7d8f A |
384 | // ------------------------------------- |
385 | // Gets the data type of this Formattable object. | |
386 | Formattable::Type | |
387 | Formattable::getType() const | |
388 | { | |
389 | return fType; | |
390 | } | |
391 | ||
374ca955 A |
392 | UBool |
393 | Formattable::isNumeric() const { | |
394 | switch (fType) { | |
395 | case kDouble: | |
396 | case kLong: | |
397 | case kInt64: | |
398 | return TRUE; | |
399 | default: | |
400 | return FALSE; | |
401 | } | |
402 | } | |
403 | ||
404 | // ------------------------------------- | |
405 | int32_t | |
406 | //Formattable::getLong(UErrorCode* status) const | |
407 | Formattable::getLong(UErrorCode& status) const | |
408 | { | |
409 | if (U_FAILURE(status)) { | |
410 | return 0; | |
411 | } | |
412 | ||
413 | switch (fType) { | |
414 | case Formattable::kLong: | |
415 | return (int32_t)fValue.fInt64; | |
57a6839d | 416 | case Formattable::kInt64: |
374ca955 A |
417 | if (fValue.fInt64 > INT32_MAX) { |
418 | status = U_INVALID_FORMAT_ERROR; | |
419 | return INT32_MAX; | |
420 | } else if (fValue.fInt64 < INT32_MIN) { | |
421 | status = U_INVALID_FORMAT_ERROR; | |
422 | return INT32_MIN; | |
423 | } else { | |
424 | return (int32_t)fValue.fInt64; | |
425 | } | |
426 | case Formattable::kDouble: | |
427 | if (fValue.fDouble > INT32_MAX) { | |
428 | status = U_INVALID_FORMAT_ERROR; | |
429 | return INT32_MAX; | |
430 | } else if (fValue.fDouble < INT32_MIN) { | |
431 | status = U_INVALID_FORMAT_ERROR; | |
432 | return INT32_MIN; | |
433 | } else { | |
434 | return (int32_t)fValue.fDouble; // loses fraction | |
435 | } | |
436 | case Formattable::kObject: | |
46f4442e A |
437 | if (fValue.fObject == NULL) { |
438 | status = U_MEMORY_ALLOCATION_ERROR; | |
439 | return 0; | |
440 | } | |
374ca955 A |
441 | // TODO Later replace this with instanceof call |
442 | if (instanceOfMeasure(fValue.fObject)) { | |
443 | return ((const Measure*) fValue.fObject)-> | |
444 | getNumber().getLong(status); | |
445 | } | |
2ca993e8 A |
446 | U_FALLTHROUGH; |
447 | default: | |
374ca955 A |
448 | status = U_INVALID_FORMAT_ERROR; |
449 | return 0; | |
450 | } | |
451 | } | |
452 | ||
453 | // ------------------------------------- | |
729e4ab9 A |
454 | // Maximum int that can be represented exactly in a double. (53 bits) |
455 | // Larger ints may be rounded to a near-by value as not all are representable. | |
456 | // TODO: move this constant elsewhere, possibly configure it for different | |
457 | // floating point formats, if any non-standard ones are still in use. | |
458 | static const int64_t U_DOUBLE_MAX_EXACT_INT = 9007199254740992LL; | |
459 | ||
374ca955 A |
460 | int64_t |
461 | Formattable::getInt64(UErrorCode& status) const | |
462 | { | |
463 | if (U_FAILURE(status)) { | |
464 | return 0; | |
465 | } | |
466 | ||
467 | switch (fType) { | |
468 | case Formattable::kLong: | |
469 | case Formattable::kInt64: | |
470 | return fValue.fInt64; | |
471 | case Formattable::kDouble: | |
729e4ab9 | 472 | if (fValue.fDouble > (double)U_INT64_MAX) { |
374ca955 A |
473 | status = U_INVALID_FORMAT_ERROR; |
474 | return U_INT64_MAX; | |
729e4ab9 | 475 | } else if (fValue.fDouble < (double)U_INT64_MIN) { |
374ca955 A |
476 | status = U_INVALID_FORMAT_ERROR; |
477 | return U_INT64_MIN; | |
729e4ab9 A |
478 | } else if (fabs(fValue.fDouble) > U_DOUBLE_MAX_EXACT_INT && fDecimalNum != NULL) { |
479 | int64_t val = fDecimalNum->getInt64(); | |
480 | if (val != 0) { | |
481 | return val; | |
482 | } else { | |
483 | status = U_INVALID_FORMAT_ERROR; | |
484 | return fValue.fDouble > 0 ? U_INT64_MAX : U_INT64_MIN; | |
485 | } | |
374ca955 A |
486 | } else { |
487 | return (int64_t)fValue.fDouble; | |
729e4ab9 | 488 | } |
374ca955 | 489 | case Formattable::kObject: |
46f4442e A |
490 | if (fValue.fObject == NULL) { |
491 | status = U_MEMORY_ALLOCATION_ERROR; | |
492 | return 0; | |
493 | } | |
374ca955 A |
494 | if (instanceOfMeasure(fValue.fObject)) { |
495 | return ((const Measure*) fValue.fObject)-> | |
496 | getNumber().getInt64(status); | |
497 | } | |
2ca993e8 A |
498 | U_FALLTHROUGH; |
499 | default: | |
374ca955 A |
500 | status = U_INVALID_FORMAT_ERROR; |
501 | return 0; | |
502 | } | |
503 | } | |
504 | ||
505 | // ------------------------------------- | |
506 | double | |
507 | Formattable::getDouble(UErrorCode& status) const | |
508 | { | |
509 | if (U_FAILURE(status)) { | |
510 | return 0; | |
511 | } | |
512 | ||
513 | switch (fType) { | |
514 | case Formattable::kLong: | |
515 | case Formattable::kInt64: // loses precision | |
516 | return (double)fValue.fInt64; | |
517 | case Formattable::kDouble: | |
518 | return fValue.fDouble; | |
519 | case Formattable::kObject: | |
46f4442e A |
520 | if (fValue.fObject == NULL) { |
521 | status = U_MEMORY_ALLOCATION_ERROR; | |
522 | return 0; | |
523 | } | |
374ca955 A |
524 | // TODO Later replace this with instanceof call |
525 | if (instanceOfMeasure(fValue.fObject)) { | |
526 | return ((const Measure*) fValue.fObject)-> | |
527 | getNumber().getDouble(status); | |
528 | } | |
2ca993e8 A |
529 | U_FALLTHROUGH; |
530 | default: | |
374ca955 A |
531 | status = U_INVALID_FORMAT_ERROR; |
532 | return 0; | |
533 | } | |
534 | } | |
535 | ||
536 | const UObject* | |
537 | Formattable::getObject() const { | |
538 | return (fType == kObject) ? fValue.fObject : NULL; | |
539 | } | |
540 | ||
b75a7d8f A |
541 | // ------------------------------------- |
542 | // Sets the value to a double value d. | |
543 | ||
544 | void | |
545 | Formattable::setDouble(double d) | |
546 | { | |
547 | dispose(); | |
548 | fType = kDouble; | |
549 | fValue.fDouble = d; | |
550 | } | |
551 | ||
552 | // ------------------------------------- | |
553 | // Sets the value to a long value l. | |
554 | ||
555 | void | |
556 | Formattable::setLong(int32_t l) | |
557 | { | |
558 | dispose(); | |
559 | fType = kLong; | |
374ca955 A |
560 | fValue.fInt64 = l; |
561 | } | |
562 | ||
563 | // ------------------------------------- | |
564 | // Sets the value to an int64 value ll. | |
565 | ||
566 | void | |
567 | Formattable::setInt64(int64_t ll) | |
568 | { | |
569 | dispose(); | |
570 | fType = kInt64; | |
571 | fValue.fInt64 = ll; | |
b75a7d8f A |
572 | } |
573 | ||
574 | // ------------------------------------- | |
575 | // Sets the value to a Date instance d. | |
576 | ||
577 | void | |
578 | Formattable::setDate(UDate d) | |
579 | { | |
580 | dispose(); | |
581 | fType = kDate; | |
582 | fValue.fDate = d; | |
583 | } | |
584 | ||
585 | // ------------------------------------- | |
586 | // Sets the value to a string value stringToCopy. | |
587 | ||
588 | void | |
589 | Formattable::setString(const UnicodeString& stringToCopy) | |
590 | { | |
591 | dispose(); | |
592 | fType = kString; | |
593 | fValue.fString = new UnicodeString(stringToCopy); | |
594 | } | |
595 | ||
596 | // ------------------------------------- | |
597 | // Sets the value to an array of Formattable objects. | |
598 | ||
599 | void | |
600 | Formattable::setArray(const Formattable* array, int32_t count) | |
601 | { | |
602 | dispose(); | |
603 | fType = kArray; | |
604 | fValue.fArrayAndCount.fArray = createArrayCopy(array, count); | |
605 | fValue.fArrayAndCount.fCount = count; | |
606 | } | |
607 | ||
608 | // ------------------------------------- | |
609 | // Adopts the stringToAdopt value. | |
610 | ||
611 | void | |
612 | Formattable::adoptString(UnicodeString* stringToAdopt) | |
613 | { | |
614 | dispose(); | |
615 | fType = kString; | |
616 | fValue.fString = stringToAdopt; | |
617 | } | |
618 | ||
619 | // ------------------------------------- | |
620 | // Adopts the array value and its count. | |
621 | ||
622 | void | |
623 | Formattable::adoptArray(Formattable* array, int32_t count) | |
624 | { | |
625 | dispose(); | |
626 | fType = kArray; | |
627 | fValue.fArrayAndCount.fArray = array; | |
628 | fValue.fArrayAndCount.fCount = count; | |
629 | } | |
630 | ||
374ca955 A |
631 | void |
632 | Formattable::adoptObject(UObject* objectToAdopt) { | |
633 | dispose(); | |
634 | fType = kObject; | |
635 | fValue.fObject = objectToAdopt; | |
636 | } | |
637 | ||
638 | // ------------------------------------- | |
639 | UnicodeString& | |
640 | Formattable::getString(UnicodeString& result, UErrorCode& status) const | |
641 | { | |
642 | if (fType != kString) { | |
643 | setError(status, U_INVALID_FORMAT_ERROR); | |
644 | result.setToBogus(); | |
645 | } else { | |
46f4442e A |
646 | if (fValue.fString == NULL) { |
647 | setError(status, U_MEMORY_ALLOCATION_ERROR); | |
648 | } else { | |
649 | result = *fValue.fString; | |
650 | } | |
374ca955 A |
651 | } |
652 | return result; | |
653 | } | |
654 | ||
655 | // ------------------------------------- | |
656 | const UnicodeString& | |
657 | Formattable::getString(UErrorCode& status) const | |
658 | { | |
659 | if (fType != kString) { | |
660 | setError(status, U_INVALID_FORMAT_ERROR); | |
661 | return *getBogus(); | |
662 | } | |
46f4442e A |
663 | if (fValue.fString == NULL) { |
664 | setError(status, U_MEMORY_ALLOCATION_ERROR); | |
665 | return *getBogus(); | |
666 | } | |
374ca955 A |
667 | return *fValue.fString; |
668 | } | |
669 | ||
670 | // ------------------------------------- | |
671 | UnicodeString& | |
672 | Formattable::getString(UErrorCode& status) | |
673 | { | |
674 | if (fType != kString) { | |
675 | setError(status, U_INVALID_FORMAT_ERROR); | |
676 | return *getBogus(); | |
677 | } | |
46f4442e A |
678 | if (fValue.fString == NULL) { |
679 | setError(status, U_MEMORY_ALLOCATION_ERROR); | |
680 | return *getBogus(); | |
681 | } | |
374ca955 A |
682 | return *fValue.fString; |
683 | } | |
684 | ||
685 | // ------------------------------------- | |
686 | const Formattable* | |
687 | Formattable::getArray(int32_t& count, UErrorCode& status) const | |
688 | { | |
689 | if (fType != kArray) { | |
690 | setError(status, U_INVALID_FORMAT_ERROR); | |
691 | count = 0; | |
692 | return NULL; | |
693 | } | |
694 | count = fValue.fArrayAndCount.fCount; | |
695 | return fValue.fArrayAndCount.fArray; | |
696 | } | |
697 | ||
698 | // ------------------------------------- | |
699 | // Gets the bogus string, ensures mondo bogosity. | |
700 | ||
701 | UnicodeString* | |
702 | Formattable::getBogus() const | |
703 | { | |
704 | return (UnicodeString*)&fBogus; /* cast away const :-( */ | |
705 | } | |
706 | ||
729e4ab9 A |
707 | |
708 | // -------------------------------------- | |
709 | StringPiece Formattable::getDecimalNumber(UErrorCode &status) { | |
710 | if (U_FAILURE(status)) { | |
711 | return ""; | |
712 | } | |
713 | if (fDecimalStr != NULL) { | |
57a6839d | 714 | return fDecimalStr->toStringPiece(); |
729e4ab9 A |
715 | } |
716 | ||
57a6839d A |
717 | CharString *decimalStr = internalGetCharString(status); |
718 | if(decimalStr == NULL) { | |
719 | return ""; // getDecimalNumber returns "" for error cases | |
720 | } else { | |
721 | return decimalStr->toStringPiece(); | |
722 | } | |
723 | } | |
724 | ||
725 | CharString *Formattable::internalGetCharString(UErrorCode &status) { | |
726 | if(fDecimalStr == NULL) { | |
727 | if (fDecimalNum == NULL) { | |
729e4ab9 A |
728 | // No decimal number for the formattable yet. Which means the value was |
729 | // set directly by the user as an int, int64 or double. If the value came | |
730 | // from parsing, or from the user setting a decimal number, fDecimalNum | |
731 | // would already be set. | |
732 | // | |
57a6839d | 733 | fDecimalNum = new DigitList; // TODO: use internal digit list |
729e4ab9 | 734 | if (fDecimalNum == NULL) { |
57a6839d A |
735 | status = U_MEMORY_ALLOCATION_ERROR; |
736 | return NULL; | |
729e4ab9 A |
737 | } |
738 | ||
739 | switch (fType) { | |
740 | case kDouble: | |
57a6839d A |
741 | fDecimalNum->set(this->getDouble()); |
742 | break; | |
729e4ab9 | 743 | case kLong: |
57a6839d A |
744 | fDecimalNum->set(this->getLong()); |
745 | break; | |
729e4ab9 | 746 | case kInt64: |
57a6839d A |
747 | fDecimalNum->set(this->getInt64()); |
748 | break; | |
729e4ab9 | 749 | default: |
57a6839d A |
750 | // The formattable's value is not a numeric type. |
751 | status = U_INVALID_STATE_ERROR; | |
752 | return NULL; | |
729e4ab9 | 753 | } |
57a6839d | 754 | } |
729e4ab9 | 755 | |
0f5d89e8 A |
756 | if (fDecimalQuantity == NULL) { |
757 | // No decimal number for the formattable yet... | |
758 | LocalPointer<DecimalQuantity> dq(new DecimalQuantity(), status); | |
759 | if (U_FAILURE(status)) { return nullptr; } | |
760 | populateDecimalQuantity(*dq, status); | |
761 | if (U_FAILURE(status)) { return nullptr; } | |
762 | fDecimalQuantity = dq.orphan(); | |
763 | } | |
764 | ||
57a6839d A |
765 | fDecimalStr = new CharString; |
766 | if (fDecimalStr == NULL) { | |
729e4ab9 | 767 | status = U_MEMORY_ALLOCATION_ERROR; |
57a6839d A |
768 | return NULL; |
769 | } | |
770 | fDecimalNum->getDecimal(*fDecimalStr, status); | |
729e4ab9 | 771 | } |
57a6839d | 772 | return fDecimalStr; |
729e4ab9 A |
773 | } |
774 | ||
0f5d89e8 A |
775 | void |
776 | Formattable::populateDecimalQuantity(number::impl::DecimalQuantity& output, UErrorCode& status) const { | |
777 | if (fDecimalQuantity != nullptr) { | |
778 | output = *fDecimalQuantity; | |
779 | return; | |
780 | } | |
781 | ||
782 | switch (fType) { | |
783 | case kDouble: | |
784 | output.setToDouble(this->getDouble()); | |
785 | output.roundToInfinity(); | |
786 | break; | |
787 | case kLong: | |
788 | output.setToInt(this->getLong()); | |
789 | break; | |
790 | case kInt64: | |
791 | output.setToLong(this->getInt64()); | |
792 | break; | |
793 | default: | |
794 | // The formattable's value is not a numeric type. | |
795 | status = U_INVALID_STATE_ERROR; | |
796 | } | |
797 | } | |
729e4ab9 | 798 | |
51004dcb A |
799 | DigitList * |
800 | Formattable::getInternalDigitList() { | |
801 | FmtStackData *stackData = (FmtStackData*)fStackData; | |
802 | if(fDecimalNum != &(stackData->stackDecimalNum)) { | |
803 | delete fDecimalNum; | |
804 | fDecimalNum = new (&(stackData->stackDecimalNum), kOnStack) DigitList(); | |
805 | } else { | |
806 | fDecimalNum->clear(); | |
807 | } | |
808 | return fDecimalNum; | |
809 | } | |
729e4ab9 A |
810 | |
811 | // --------------------------------------- | |
812 | void | |
813 | Formattable::adoptDigitList(DigitList *dl) { | |
51004dcb A |
814 | if(fDecimalNum==dl) { |
815 | fDecimalNum = NULL; // don't delete | |
816 | } | |
817 | dispose(); | |
818 | ||
819 | fDecimalNum = dl; | |
729e4ab9 | 820 | |
51004dcb A |
821 | if(dl==NULL) { // allow adoptDigitList(NULL) to clear |
822 | return; | |
823 | } | |
729e4ab9 A |
824 | |
825 | // Set the value into the Union of simple type values. | |
826 | // Cannot use the set() functions because they would delete the fDecimalNum value, | |
827 | ||
828 | if (fDecimalNum->fitsIntoLong(FALSE)) { | |
829 | fType = kLong; | |
830 | fValue.fInt64 = fDecimalNum->getLong(); | |
831 | } else if (fDecimalNum->fitsIntoInt64(FALSE)) { | |
832 | fType = kInt64; | |
833 | fValue.fInt64 = fDecimalNum->getInt64(); | |
834 | } else { | |
835 | fType = kDouble; | |
836 | fValue.fDouble = fDecimalNum->getDouble(); | |
837 | } | |
838 | } | |
839 | ||
0f5d89e8 A |
840 | // --------------------------------------- |
841 | void | |
842 | Formattable::adoptDecimalQuantity(DecimalQuantity *dq) { | |
843 | if (fDecimalQuantity != NULL) { | |
844 | delete fDecimalQuantity; | |
845 | } | |
846 | fDecimalQuantity = dq; | |
847 | if (dq == NULL) { // allow adoptDigitList(NULL) to clear | |
848 | return; | |
849 | } | |
850 | ||
851 | // Set the value into the Union of simple type values. | |
852 | // Cannot use the set() functions because they would delete the fDecimalNum value. | |
853 | if (fDecimalQuantity->fitsInLong()) { | |
854 | fValue.fInt64 = fDecimalQuantity->toLong(); | |
855 | if (fValue.fInt64 <= INT32_MAX && fValue.fInt64 >= INT32_MIN) { | |
856 | fType = kLong; | |
857 | } else { | |
858 | fType = kInt64; | |
859 | } | |
860 | } else { | |
861 | fType = kDouble; | |
862 | fValue.fDouble = fDecimalQuantity->toDouble(); | |
863 | } | |
864 | } | |
865 | ||
729e4ab9 A |
866 | |
867 | // --------------------------------------- | |
868 | void | |
f3c0d7a5 | 869 | Formattable::setDecimalNumber(StringPiece numberString, UErrorCode &status) { |
729e4ab9 A |
870 | if (U_FAILURE(status)) { |
871 | return; | |
872 | } | |
873 | dispose(); | |
874 | ||
875 | // Copy the input string and nul-terminate it. | |
876 | // The decNumber library requires nul-terminated input. StringPiece input | |
877 | // is not guaranteed nul-terminated. Too bad. | |
878 | // CharString automatically adds the nul. | |
51004dcb | 879 | DigitList *dnum = new DigitList(); // TODO: use getInternalDigitList |
729e4ab9 A |
880 | if (dnum == NULL) { |
881 | status = U_MEMORY_ALLOCATION_ERROR; | |
882 | return; | |
883 | } | |
884 | dnum->set(CharString(numberString, status).toStringPiece(), status); | |
885 | if (U_FAILURE(status)) { | |
886 | delete dnum; | |
887 | return; // String didn't contain a decimal number. | |
888 | } | |
889 | adoptDigitList(dnum); | |
890 | ||
0f5d89e8 A |
891 | auto* dq = new DecimalQuantity(); |
892 | dq->setToDecNumber(numberString, status); | |
893 | adoptDecimalQuantity(dq); | |
894 | ||
729e4ab9 A |
895 | // Note that we do not hang on to the caller's input string. |
896 | // If we are asked for the string, we will regenerate one from fDecimalNum. | |
897 | } | |
898 | ||
b75a7d8f A |
899 | #if 0 |
900 | //---------------------------------------------------- | |
901 | // console I/O | |
902 | //---------------------------------------------------- | |
903 | #ifdef _DEBUG | |
904 | ||
b75a7d8f A |
905 | #include <iostream> |
906 | using namespace std; | |
b75a7d8f A |
907 | |
908 | #include "unicode/datefmt.h" | |
909 | #include "unistrm.h" | |
910 | ||
911 | class FormattableStreamer /* not : public UObject because all methods are static */ { | |
912 | public: | |
913 | static void streamOut(ostream& stream, const Formattable& obj); | |
914 | ||
915 | private: | |
916 | FormattableStreamer() {} // private - forbid instantiation | |
917 | }; | |
918 | ||
919 | // This is for debugging purposes only. This will send a displayable | |
920 | // form of the Formattable object to the output stream. | |
921 | ||
922 | void | |
923 | FormattableStreamer::streamOut(ostream& stream, const Formattable& obj) | |
924 | { | |
925 | static DateFormat *defDateFormat = 0; | |
926 | ||
927 | UnicodeString buffer; | |
928 | switch(obj.getType()) { | |
929 | case Formattable::kDate : | |
930 | // Creates a DateFormat instance for formatting the | |
931 | // Date instance. | |
932 | if (defDateFormat == 0) { | |
933 | defDateFormat = DateFormat::createInstance(); | |
934 | } | |
935 | defDateFormat->format(obj.getDate(), buffer); | |
936 | stream << buffer; | |
937 | break; | |
938 | case Formattable::kDouble : | |
939 | // Output the double as is. | |
940 | stream << obj.getDouble() << 'D'; | |
941 | break; | |
942 | case Formattable::kLong : | |
943 | // Output the double as is. | |
944 | stream << obj.getLong() << 'L'; | |
945 | break; | |
946 | case Formattable::kString: | |
947 | // Output the double as is. Please see UnicodeString console | |
948 | // I/O routine for more details. | |
949 | stream << '"' << obj.getString(buffer) << '"'; | |
950 | break; | |
951 | case Formattable::kArray: | |
952 | int32_t i, count; | |
953 | const Formattable* array; | |
954 | array = obj.getArray(count); | |
955 | stream << '['; | |
956 | // Recursively calling the console I/O routine for each element in the array. | |
957 | for (i=0; i<count; ++i) { | |
958 | FormattableStreamer::streamOut(stream, array[i]); | |
959 | stream << ( (i==(count-1)) ? "" : ", " ); | |
960 | } | |
961 | stream << ']'; | |
962 | break; | |
963 | default: | |
964 | // Not a recognizable Formattable object. | |
965 | stream << "INVALID_Formattable"; | |
966 | } | |
967 | stream.flush(); | |
968 | } | |
969 | #endif | |
970 | ||
971 | #endif | |
972 | ||
973 | U_NAMESPACE_END | |
974 | ||
57a6839d A |
975 | /* ---- UFormattable implementation ---- */ |
976 | ||
977 | U_NAMESPACE_USE | |
978 | ||
979 | U_DRAFT UFormattable* U_EXPORT2 | |
980 | ufmt_open(UErrorCode *status) { | |
981 | if( U_FAILURE(*status) ) { | |
982 | return NULL; | |
983 | } | |
984 | UFormattable *fmt = (new Formattable())->toUFormattable(); | |
985 | ||
986 | if( fmt == NULL ) { | |
987 | *status = U_MEMORY_ALLOCATION_ERROR; | |
988 | } | |
989 | return fmt; | |
990 | } | |
991 | ||
992 | U_DRAFT void U_EXPORT2 | |
993 | ufmt_close(UFormattable *fmt) { | |
994 | Formattable *obj = Formattable::fromUFormattable(fmt); | |
995 | ||
996 | delete obj; | |
997 | } | |
998 | ||
999 | U_INTERNAL UFormattableType U_EXPORT2 | |
1000 | ufmt_getType(const UFormattable *fmt, UErrorCode *status) { | |
1001 | if(U_FAILURE(*status)) { | |
1002 | return (UFormattableType)UFMT_COUNT; | |
1003 | } | |
1004 | const Formattable *obj = Formattable::fromUFormattable(fmt); | |
1005 | return (UFormattableType)obj->getType(); | |
1006 | } | |
1007 | ||
1008 | ||
1009 | U_INTERNAL UBool U_EXPORT2 | |
1010 | ufmt_isNumeric(const UFormattable *fmt) { | |
1011 | const Formattable *obj = Formattable::fromUFormattable(fmt); | |
1012 | return obj->isNumeric(); | |
1013 | } | |
1014 | ||
1015 | U_DRAFT UDate U_EXPORT2 | |
1016 | ufmt_getDate(const UFormattable *fmt, UErrorCode *status) { | |
1017 | const Formattable *obj = Formattable::fromUFormattable(fmt); | |
1018 | ||
1019 | return obj->getDate(*status); | |
1020 | } | |
1021 | ||
1022 | U_DRAFT double U_EXPORT2 | |
1023 | ufmt_getDouble(UFormattable *fmt, UErrorCode *status) { | |
1024 | Formattable *obj = Formattable::fromUFormattable(fmt); | |
1025 | ||
1026 | return obj->getDouble(*status); | |
1027 | } | |
1028 | ||
1029 | U_DRAFT int32_t U_EXPORT2 | |
1030 | ufmt_getLong(UFormattable *fmt, UErrorCode *status) { | |
1031 | Formattable *obj = Formattable::fromUFormattable(fmt); | |
1032 | ||
1033 | return obj->getLong(*status); | |
1034 | } | |
1035 | ||
1036 | ||
1037 | U_DRAFT const void *U_EXPORT2 | |
1038 | ufmt_getObject(const UFormattable *fmt, UErrorCode *status) { | |
1039 | const Formattable *obj = Formattable::fromUFormattable(fmt); | |
1040 | ||
1041 | const void *ret = obj->getObject(); | |
1042 | if( ret==NULL && | |
1043 | (obj->getType() != Formattable::kObject) && | |
1044 | U_SUCCESS( *status )) { | |
1045 | *status = U_INVALID_FORMAT_ERROR; | |
1046 | } | |
1047 | return ret; | |
1048 | } | |
1049 | ||
1050 | U_DRAFT const UChar* U_EXPORT2 | |
1051 | ufmt_getUChars(UFormattable *fmt, int32_t *len, UErrorCode *status) { | |
1052 | Formattable *obj = Formattable::fromUFormattable(fmt); | |
1053 | ||
1054 | // avoid bogosity by checking the type first. | |
1055 | if( obj->getType() != Formattable::kString ) { | |
1056 | if( U_SUCCESS(*status) ){ | |
1057 | *status = U_INVALID_FORMAT_ERROR; | |
1058 | } | |
1059 | return NULL; | |
1060 | } | |
1061 | ||
1062 | // This should return a valid string | |
1063 | UnicodeString &str = obj->getString(*status); | |
1064 | if( U_SUCCESS(*status) && len != NULL ) { | |
1065 | *len = str.length(); | |
1066 | } | |
1067 | return str.getTerminatedBuffer(); | |
1068 | } | |
1069 | ||
1070 | U_DRAFT int32_t U_EXPORT2 | |
1071 | ufmt_getArrayLength(const UFormattable* fmt, UErrorCode *status) { | |
1072 | const Formattable *obj = Formattable::fromUFormattable(fmt); | |
1073 | ||
1074 | int32_t count; | |
1075 | (void)obj->getArray(count, *status); | |
1076 | return count; | |
1077 | } | |
1078 | ||
1079 | U_DRAFT UFormattable * U_EXPORT2 | |
1080 | ufmt_getArrayItemByIndex(UFormattable* fmt, int32_t n, UErrorCode *status) { | |
1081 | Formattable *obj = Formattable::fromUFormattable(fmt); | |
1082 | int32_t count; | |
1083 | (void)obj->getArray(count, *status); | |
1084 | if(U_FAILURE(*status)) { | |
1085 | return NULL; | |
1086 | } else if(n<0 || n>=count) { | |
1087 | setError(*status, U_INDEX_OUTOFBOUNDS_ERROR); | |
1088 | return NULL; | |
1089 | } else { | |
1090 | return (*obj)[n].toUFormattable(); // returns non-const Formattable | |
1091 | } | |
1092 | } | |
1093 | ||
1094 | U_DRAFT const char * U_EXPORT2 | |
1095 | ufmt_getDecNumChars(UFormattable *fmt, int32_t *len, UErrorCode *status) { | |
1096 | if(U_FAILURE(*status)) { | |
1097 | return ""; | |
1098 | } | |
1099 | Formattable *obj = Formattable::fromUFormattable(fmt); | |
1100 | CharString *charString = obj->internalGetCharString(*status); | |
1101 | if(U_FAILURE(*status)) { | |
1102 | return ""; | |
1103 | } | |
1104 | if(charString == NULL) { | |
1105 | *status = U_MEMORY_ALLOCATION_ERROR; | |
1106 | return ""; | |
1107 | } else { | |
1108 | if(len!=NULL) { | |
1109 | *len = charString->length(); | |
1110 | } | |
1111 | return charString->data(); | |
1112 | } | |
1113 | } | |
1114 | ||
1115 | U_DRAFT int64_t U_EXPORT2 | |
1116 | ufmt_getInt64(UFormattable *fmt, UErrorCode *status) { | |
1117 | Formattable *obj = Formattable::fromUFormattable(fmt); | |
1118 | return obj->getInt64(*status); | |
1119 | } | |
1120 | ||
b75a7d8f A |
1121 | #endif /* #if !UCONFIG_NO_FORMATTING */ |
1122 | ||
1123 | //eof |