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