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