]> git.saurik.com Git - apple/icu.git/blame_incremental - icuSources/i18n/fmtable.cpp
ICU-551.51.4.tar.gz
[apple/icu.git] / icuSources / i18n / fmtable.cpp
... / ...
CommitLineData
1/*
2*******************************************************************************
3* Copyright (C) 1997-2014, International Business Machines Corporation and *
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
20#include <math.h>
21#include "unicode/fmtable.h"
22#include "unicode/ustring.h"
23#include "unicode/measure.h"
24#include "unicode/curramt.h"
25#include "unicode/uformattable.h"
26#include "charstr.h"
27#include "cmemory.h"
28#include "cstring.h"
29#include "decNumber.h"
30#include "digitlst.h"
31#include "fmtableimp.h"
32
33// *****************************************************************************
34// class Formattable
35// *****************************************************************************
36
37U_NAMESPACE_BEGIN
38
39UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Formattable)
40
41
42//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
43
44// NOTE: As of 3.0, there are limitations to the UObject API. It does
45// not (yet) support cloning, operator=, nor operator==. To
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.
53static inline UBool objectEquals(const UObject* a, const UObject* b) {
54 // LATER: return *a == *b;
55 return *((const Measure*) a) == *((const Measure*) b);
56}
57
58// Return a clone of *a.
59static inline UObject* objectClone(const UObject* a) {
60 // LATER: return a->clone();
61 return ((const Measure*) a)->clone();
62}
63
64// Return TRUE if *a is an instance of Measure.
65static inline UBool instanceOfMeasure(const UObject* a) {
66 return dynamic_cast<const Measure*>(a) != NULL;
67}
68
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 */
76static Formattable* createArrayCopy(const Formattable* array, int32_t count) {
77 Formattable *result = new Formattable[count];
78 if (result != NULL) {
79 for (int32_t i=0; i<count; ++i)
80 result[i] = array[i]; // Don't memcpy!
81 }
82 return result;
83}
84
85//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
86
87/**
88 * Set 'ec' to 'err' only if 'ec' is not already set to a failing UErrorCode.
89 */
90static void setError(UErrorCode& ec, UErrorCode err) {
91 if (U_SUCCESS(ec)) {
92 ec = err;
93 }
94}
95
96//
97// Common initialization code, shared by constructors.
98// Put everything into a known state.
99//
100void Formattable::init() {
101 fValue.fInt64 = 0;
102 fType = kLong;
103 fDecimalStr = NULL;
104 fDecimalNum = NULL;
105 fBogus.setToBogus();
106}
107
108// -------------------------------------
109// default constructor.
110// Creates a formattable object with a long value 0.
111
112Formattable::Formattable() {
113 init();
114}
115
116// -------------------------------------
117// Creates a formattable object with a Date instance.
118
119Formattable::Formattable(UDate date, ISDATE /*isDate*/)
120{
121 init();
122 fType = kDate;
123 fValue.fDate = date;
124}
125
126// -------------------------------------
127// Creates a formattable object with a double value.
128
129Formattable::Formattable(double value)
130{
131 init();
132 fType = kDouble;
133 fValue.fDouble = value;
134}
135
136// -------------------------------------
137// Creates a formattable object with an int32_t value.
138
139Formattable::Formattable(int32_t value)
140{
141 init();
142 fValue.fInt64 = value;
143}
144
145// -------------------------------------
146// Creates a formattable object with an int64_t value.
147
148Formattable::Formattable(int64_t value)
149{
150 init();
151 fType = kInt64;
152 fValue.fInt64 = value;
153}
154
155// -------------------------------------
156// Creates a formattable object with a decimal number value from a string.
157
158Formattable::Formattable(const StringPiece &number, UErrorCode &status) {
159 init();
160 setDecimalNumber(number, status);
161}
162
163
164// -------------------------------------
165// Creates a formattable object with a UnicodeString instance.
166
167Formattable::Formattable(const UnicodeString& stringToCopy)
168{
169 init();
170 fType = kString;
171 fValue.fString = new UnicodeString(stringToCopy);
172}
173
174// -------------------------------------
175// Creates a formattable object with a UnicodeString* value.
176// (adopting symantics)
177
178Formattable::Formattable(UnicodeString* stringToAdopt)
179{
180 init();
181 fType = kString;
182 fValue.fString = stringToAdopt;
183}
184
185Formattable::Formattable(UObject* objectToAdopt)
186{
187 init();
188 fType = kObject;
189 fValue.fObject = objectToAdopt;
190}
191
192// -------------------------------------
193
194Formattable::Formattable(const Formattable* arrayToCopy, int32_t count)
195 : UObject(), fType(kArray)
196{
197 init();
198 fType = kArray;
199 fValue.fArrayAndCount.fArray = createArrayCopy(arrayToCopy, count);
200 fValue.fArrayAndCount.fCount = count;
201}
202
203// -------------------------------------
204// copy constructor
205
206
207Formattable::Formattable(const Formattable &source)
208 : UObject(*this)
209{
210 init();
211 *this = source;
212}
213
214// -------------------------------------
215// assignment operator
216
217Formattable&
218Formattable::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:
244 case kInt64:
245 // Sets the long value.
246 fValue.fInt64 = source.fValue.fInt64;
247 break;
248 case kDate:
249 // Sets the Date value.
250 fValue.fDate = source.fValue.fDate;
251 break;
252 case kObject:
253 fValue.fObject = objectClone(source.fValue.fObject);
254 break;
255 }
256
257 UErrorCode status = U_ZERO_ERROR;
258 if (source.fDecimalNum != NULL) {
259 fDecimalNum = new DigitList(*source.fDecimalNum); // TODO: use internal digit list
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 }
268 }
269 return *this;
270}
271
272// -------------------------------------
273
274UBool
275Formattable::operator==(const Formattable& that) const
276{
277 int32_t i;
278
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.
285 UBool equal = TRUE;
286 switch (fType) {
287 case kDate:
288 equal = (fValue.fDate == that.fValue.fDate);
289 break;
290 case kDouble:
291 equal = (fValue.fDouble == that.fValue.fDouble);
292 break;
293 case kLong:
294 case kInt64:
295 equal = (fValue.fInt64 == that.fValue.fInt64);
296 break;
297 case kString:
298 equal = (*(fValue.fString) == *(that.fValue.fString));
299 break;
300 case kArray:
301 if (fValue.fArrayAndCount.fCount != that.fValue.fArrayAndCount.fCount) {
302 equal = FALSE;
303 break;
304 }
305 // Checks each element for equality.
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:
314 if (fValue.fObject == NULL || that.fValue.fObject == NULL) {
315 equal = FALSE;
316 } else {
317 equal = objectEquals(fValue.fObject, that.fValue.fObject);
318 }
319 break;
320 }
321
322 // TODO: compare digit lists if numeric.
323 return equal;
324}
325
326// -------------------------------------
327
328Formattable::~Formattable()
329{
330 dispose();
331}
332
333// -------------------------------------
334
335void 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;
345 case kObject:
346 delete fValue.fObject;
347 break;
348 default:
349 break;
350 }
351
352 fType = kLong;
353 fValue.fInt64 = 0;
354
355 delete fDecimalStr;
356 fDecimalStr = NULL;
357
358 FmtStackData *stackData = (FmtStackData*)fStackData;
359 if(fDecimalNum != &(stackData->stackDecimalNum)) {
360 delete fDecimalNum;
361 } else {
362 fDecimalNum->~DigitList(); // destruct, don't deallocate
363 }
364 fDecimalNum = NULL;
365}
366
367Formattable *
368Formattable::clone() const {
369 return new Formattable(*this);
370}
371
372// -------------------------------------
373// Gets the data type of this Formattable object.
374Formattable::Type
375Formattable::getType() const
376{
377 return fType;
378}
379
380UBool
381Formattable::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// -------------------------------------
393int32_t
394//Formattable::getLong(UErrorCode* status) const
395Formattable::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;
404 case Formattable::kInt64:
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:
425 if (fValue.fObject == NULL) {
426 status = U_MEMORY_ALLOCATION_ERROR;
427 return 0;
428 }
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// -------------------------------------
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.
445static const int64_t U_DOUBLE_MAX_EXACT_INT = 9007199254740992LL;
446
447int64_t
448Formattable::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:
459 if (fValue.fDouble > (double)U_INT64_MAX) {
460 status = U_INVALID_FORMAT_ERROR;
461 return U_INT64_MAX;
462 } else if (fValue.fDouble < (double)U_INT64_MIN) {
463 status = U_INVALID_FORMAT_ERROR;
464 return U_INT64_MIN;
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 }
473 } else {
474 return (int64_t)fValue.fDouble;
475 }
476 case Formattable::kObject:
477 if (fValue.fObject == NULL) {
478 status = U_MEMORY_ALLOCATION_ERROR;
479 return 0;
480 }
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// -------------------------------------
492double
493Formattable::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:
506 if (fValue.fObject == NULL) {
507 status = U_MEMORY_ALLOCATION_ERROR;
508 return 0;
509 }
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
521const UObject*
522Formattable::getObject() const {
523 return (fType == kObject) ? fValue.fObject : NULL;
524}
525
526// -------------------------------------
527// Sets the value to a double value d.
528
529void
530Formattable::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
540void
541Formattable::setLong(int32_t l)
542{
543 dispose();
544 fType = kLong;
545 fValue.fInt64 = l;
546}
547
548// -------------------------------------
549// Sets the value to an int64 value ll.
550
551void
552Formattable::setInt64(int64_t ll)
553{
554 dispose();
555 fType = kInt64;
556 fValue.fInt64 = ll;
557}
558
559// -------------------------------------
560// Sets the value to a Date instance d.
561
562void
563Formattable::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
573void
574Formattable::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
584void
585Formattable::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
596void
597Formattable::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
607void
608Formattable::adoptArray(Formattable* array, int32_t count)
609{
610 dispose();
611 fType = kArray;
612 fValue.fArrayAndCount.fArray = array;
613 fValue.fArrayAndCount.fCount = count;
614}
615
616void
617Formattable::adoptObject(UObject* objectToAdopt) {
618 dispose();
619 fType = kObject;
620 fValue.fObject = objectToAdopt;
621}
622
623// -------------------------------------
624UnicodeString&
625Formattable::getString(UnicodeString& result, UErrorCode& status) const
626{
627 if (fType != kString) {
628 setError(status, U_INVALID_FORMAT_ERROR);
629 result.setToBogus();
630 } else {
631 if (fValue.fString == NULL) {
632 setError(status, U_MEMORY_ALLOCATION_ERROR);
633 } else {
634 result = *fValue.fString;
635 }
636 }
637 return result;
638}
639
640// -------------------------------------
641const UnicodeString&
642Formattable::getString(UErrorCode& status) const
643{
644 if (fType != kString) {
645 setError(status, U_INVALID_FORMAT_ERROR);
646 return *getBogus();
647 }
648 if (fValue.fString == NULL) {
649 setError(status, U_MEMORY_ALLOCATION_ERROR);
650 return *getBogus();
651 }
652 return *fValue.fString;
653}
654
655// -------------------------------------
656UnicodeString&
657Formattable::getString(UErrorCode& status)
658{
659 if (fType != kString) {
660 setError(status, U_INVALID_FORMAT_ERROR);
661 return *getBogus();
662 }
663 if (fValue.fString == NULL) {
664 setError(status, U_MEMORY_ALLOCATION_ERROR);
665 return *getBogus();
666 }
667 return *fValue.fString;
668}
669
670// -------------------------------------
671const Formattable*
672Formattable::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
686UnicodeString*
687Formattable::getBogus() const
688{
689 return (UnicodeString*)&fBogus; /* cast away const :-( */
690}
691
692
693// --------------------------------------
694StringPiece Formattable::getDecimalNumber(UErrorCode &status) {
695 if (U_FAILURE(status)) {
696 return "";
697 }
698 if (fDecimalStr != NULL) {
699 return fDecimalStr->toStringPiece();
700 }
701
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
710CharString *Formattable::internalGetCharString(UErrorCode &status) {
711 if(fDecimalStr == NULL) {
712 if (fDecimalNum == NULL) {
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 //
718 fDecimalNum = new DigitList; // TODO: use internal digit list
719 if (fDecimalNum == NULL) {
720 status = U_MEMORY_ALLOCATION_ERROR;
721 return NULL;
722 }
723
724 switch (fType) {
725 case kDouble:
726 fDecimalNum->set(this->getDouble());
727 break;
728 case kLong:
729 fDecimalNum->set(this->getLong());
730 break;
731 case kInt64:
732 fDecimalNum->set(this->getInt64());
733 break;
734 default:
735 // The formattable's value is not a numeric type.
736 status = U_INVALID_STATE_ERROR;
737 return NULL;
738 }
739 }
740
741 fDecimalStr = new CharString;
742 if (fDecimalStr == NULL) {
743 status = U_MEMORY_ALLOCATION_ERROR;
744 return NULL;
745 }
746 fDecimalNum->getDecimal(*fDecimalStr, status);
747 }
748 return fDecimalStr;
749}
750
751
752DigitList *
753Formattable::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}
763
764// ---------------------------------------
765void
766Formattable::adoptDigitList(DigitList *dl) {
767 if(fDecimalNum==dl) {
768 fDecimalNum = NULL; // don't delete
769 }
770 dispose();
771
772 fDecimalNum = dl;
773
774 if(dl==NULL) { // allow adoptDigitList(NULL) to clear
775 return;
776 }
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// ---------------------------------------
795void
796Formattable::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.
806 DigitList *dnum = new DigitList(); // TODO: use getInternalDigitList
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
822#if 0
823//----------------------------------------------------
824// console I/O
825//----------------------------------------------------
826#ifdef _DEBUG
827
828#include <iostream>
829using namespace std;
830
831#include "unicode/datefmt.h"
832#include "unistrm.h"
833
834class FormattableStreamer /* not : public UObject because all methods are static */ {
835public:
836 static void streamOut(ostream& stream, const Formattable& obj);
837
838private:
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
845void
846FormattableStreamer::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
896U_NAMESPACE_END
897
898/* ---- UFormattable implementation ---- */
899
900U_NAMESPACE_USE
901
902U_DRAFT UFormattable* U_EXPORT2
903ufmt_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
915U_DRAFT void U_EXPORT2
916ufmt_close(UFormattable *fmt) {
917 Formattable *obj = Formattable::fromUFormattable(fmt);
918
919 delete obj;
920}
921
922U_INTERNAL UFormattableType U_EXPORT2
923ufmt_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
932U_INTERNAL UBool U_EXPORT2
933ufmt_isNumeric(const UFormattable *fmt) {
934 const Formattable *obj = Formattable::fromUFormattable(fmt);
935 return obj->isNumeric();
936}
937
938U_DRAFT UDate U_EXPORT2
939ufmt_getDate(const UFormattable *fmt, UErrorCode *status) {
940 const Formattable *obj = Formattable::fromUFormattable(fmt);
941
942 return obj->getDate(*status);
943}
944
945U_DRAFT double U_EXPORT2
946ufmt_getDouble(UFormattable *fmt, UErrorCode *status) {
947 Formattable *obj = Formattable::fromUFormattable(fmt);
948
949 return obj->getDouble(*status);
950}
951
952U_DRAFT int32_t U_EXPORT2
953ufmt_getLong(UFormattable *fmt, UErrorCode *status) {
954 Formattable *obj = Formattable::fromUFormattable(fmt);
955
956 return obj->getLong(*status);
957}
958
959
960U_DRAFT const void *U_EXPORT2
961ufmt_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
973U_DRAFT const UChar* U_EXPORT2
974ufmt_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
993U_DRAFT int32_t U_EXPORT2
994ufmt_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
1002U_DRAFT UFormattable * U_EXPORT2
1003ufmt_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
1017U_DRAFT const char * U_EXPORT2
1018ufmt_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
1038U_DRAFT int64_t U_EXPORT2
1039ufmt_getInt64(UFormattable *fmt, UErrorCode *status) {
1040 Formattable *obj = Formattable::fromUFormattable(fmt);
1041 return obj->getInt64(*status);
1042}
1043
1044#endif /* #if !UCONFIG_NO_FORMATTING */
1045
1046//eof