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