]> git.saurik.com Git - apple/icu.git/blame - icuSources/i18n/fmtable.cpp
ICU-8.11.4.tar.gz
[apple/icu.git] / icuSources / i18n / fmtable.cpp
CommitLineData
b75a7d8f
A
1/*
2*******************************************************************************
73c04bcf 3* Copyright (C) 1997-2006, 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
20#include "unicode/fmtable.h"
374ca955
A
21#include "unicode/ustring.h"
22#include "unicode/measure.h"
23#include "unicode/curramt.h"
b75a7d8f
A
24#include "cmemory.h"
25
26// *****************************************************************************
27// class Formattable
28// *****************************************************************************
29
30U_NAMESPACE_BEGIN
31
374ca955
A
32UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Formattable)
33
34//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
35
36// NOTE: As of 3.0, there are limitations to the UObject API. It does
37// not (yet) support cloning, operator=, nor operator==. RTTI is also
38// restricted in that subtype testing is not (yet) implemented. To
39// work around this, I implement some simple inlines here. Later
40// these can be modified or removed. [alan]
41
42// NOTE: These inlines assume that all fObjects are in fact instances
43// of the Measure class, which is true as of 3.0. [alan]
44
45// Return TRUE if *a == *b.
73c04bcf 46static inline UBool objectEquals(const UObject* a, const UObject* b) {
374ca955
A
47 // LATER: return *a == *b;
48 return *((const Measure*) a) == *((const Measure*) b);
49}
50
51// Return a clone of *a.
73c04bcf 52static inline UObject* objectClone(const UObject* a) {
374ca955
A
53 // LATER: return a->clone();
54 return ((const Measure*) a)->clone();
55}
56
57// Return TRUE if *a is an instance of Measure.
73c04bcf 58static inline UBool instanceOfMeasure(const UObject* a) {
374ca955
A
59 // LATER: return a->instanceof(Measure::getStaticClassID());
60 return a->getDynamicClassID() ==
61 CurrencyAmount::getStaticClassID();
62}
63
73c04bcf
A
64/**
65 * Creates a new Formattable array and copies the values from the specified
66 * original.
67 * @param array the original array
68 * @param count the original array count
69 * @return the new Formattable array.
70 */
71static inline Formattable* createArrayCopy(const Formattable* array, int32_t count) {
72 Formattable *result = new Formattable[count];
73 for (int32_t i=0; i<count; ++i) result[i] = array[i]; // Don't memcpy!
74 return result;
75}
76
374ca955
A
77//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
78
79/**
80 * Set 'ec' to 'err' only if 'ec' is not already set to a failing UErrorCode.
81 */
73c04bcf 82static inline void setError(UErrorCode& ec, UErrorCode err) {
374ca955
A
83 if (U_SUCCESS(ec)) {
84 ec = err;
85 }
86}
b75a7d8f
A
87
88// -------------------------------------
89// default constructor.
90// Creates a formattable object with a long value 0.
91
92Formattable::Formattable()
93 : UObject(), fType(kLong)
94{
374ca955
A
95 fBogus.setToBogus();
96 fValue.fInt64 = 0;
b75a7d8f
A
97}
98
99// -------------------------------------
100// Creates a formattable object with a Date instance.
101
102Formattable::Formattable(UDate date, ISDATE /*isDate*/)
103 : UObject(), fType(kDate)
104{
374ca955 105 fBogus.setToBogus();
b75a7d8f
A
106 fValue.fDate = date;
107}
108
109// -------------------------------------
110// Creates a formattable object with a double value.
111
112Formattable::Formattable(double value)
113 : UObject(), fType(kDouble)
114{
374ca955 115 fBogus.setToBogus();
b75a7d8f
A
116 fValue.fDouble = value;
117}
118
119// -------------------------------------
120// Creates a formattable object with a long value.
121
122Formattable::Formattable(int32_t value)
123 : UObject(), fType(kLong)
124{
374ca955
A
125 fBogus.setToBogus();
126 fValue.fInt64 = value;
127}
128
129// -------------------------------------
130// Creates a formattable object with a long value.
131
132Formattable::Formattable(int64_t value)
133 : UObject(), fType(kInt64)
134{
135 fBogus.setToBogus();
136 fValue.fInt64 = value;
b75a7d8f
A
137}
138
b75a7d8f
A
139// -------------------------------------
140// Creates a formattable object with a UnicodeString instance.
141
142Formattable::Formattable(const UnicodeString& stringToCopy)
143 : UObject(), fType(kString)
144{
374ca955 145 fBogus.setToBogus();
b75a7d8f
A
146 fValue.fString = new UnicodeString(stringToCopy);
147}
148
149// -------------------------------------
150// Creates a formattable object with a UnicodeString* value.
151// (adopting symantics)
152
153Formattable::Formattable(UnicodeString* stringToAdopt)
154 : UObject(), fType(kString)
155{
374ca955 156 fBogus.setToBogus();
b75a7d8f
A
157 fValue.fString = stringToAdopt;
158}
159
374ca955
A
160Formattable::Formattable(UObject* objectToAdopt)
161 : UObject(), fType(kObject)
162{
163 fBogus.setToBogus();
164 fValue.fObject = objectToAdopt;
165}
166
b75a7d8f
A
167// -------------------------------------
168
169Formattable::Formattable(const Formattable* arrayToCopy, int32_t count)
170 : UObject(), fType(kArray)
171{
374ca955 172 fBogus.setToBogus();
b75a7d8f
A
173 fValue.fArrayAndCount.fArray = createArrayCopy(arrayToCopy, count);
174 fValue.fArrayAndCount.fCount = count;
175}
176
177// -------------------------------------
178// copy constructor
179
180Formattable::Formattable(const Formattable &source)
181 : UObject(source), fType(kLong)
182{
374ca955 183 fBogus.setToBogus();
b75a7d8f
A
184 *this = source;
185}
186
187// -------------------------------------
188// assignment operator
189
190Formattable&
191Formattable::operator=(const Formattable& source)
192{
193 if (this != &source)
194 {
195 // Disposes the current formattable value/setting.
196 dispose();
197
198 // Sets the correct data type for this value.
199 fType = source.fType;
200 switch (fType)
201 {
202 case kArray:
203 // Sets each element in the array one by one and records the array count.
204 fValue.fArrayAndCount.fCount = source.fValue.fArrayAndCount.fCount;
205 fValue.fArrayAndCount.fArray = createArrayCopy(source.fValue.fArrayAndCount.fArray,
206 source.fValue.fArrayAndCount.fCount);
207 break;
208 case kString:
209 // Sets the string value.
210 fValue.fString = new UnicodeString(*source.fValue.fString);
211 break;
212 case kDouble:
213 // Sets the double value.
214 fValue.fDouble = source.fValue.fDouble;
215 break;
216 case kLong:
374ca955 217 case kInt64:
b75a7d8f 218 // Sets the long value.
374ca955 219 fValue.fInt64 = source.fValue.fInt64;
b75a7d8f
A
220 break;
221 case kDate:
222 // Sets the Date value.
223 fValue.fDate = source.fValue.fDate;
224 break;
374ca955
A
225 case kObject:
226 fValue.fObject = objectClone(source.fValue.fObject);
227 break;
b75a7d8f
A
228 }
229 }
230 return *this;
231}
232
233// -------------------------------------
234
235UBool
236Formattable::operator==(const Formattable& that) const
237{
374ca955
A
238 int32_t i;
239
b75a7d8f
A
240 if (this == &that) return TRUE;
241
242 // Returns FALSE if the data types are different.
243 if (fType != that.fType) return FALSE;
244
245 // Compares the actual data values.
374ca955 246 UBool equal = TRUE;
b75a7d8f
A
247 switch (fType) {
248 case kDate:
374ca955
A
249 equal = (fValue.fDate == that.fValue.fDate);
250 break;
b75a7d8f 251 case kDouble:
374ca955
A
252 equal = (fValue.fDouble == that.fValue.fDouble);
253 break;
b75a7d8f 254 case kLong:
374ca955
A
255 case kInt64:
256 equal = (fValue.fInt64 == that.fValue.fInt64);
257 break;
b75a7d8f 258 case kString:
374ca955
A
259 equal = (*(fValue.fString) == *(that.fValue.fString));
260 break;
b75a7d8f 261 case kArray:
374ca955
A
262 if (fValue.fArrayAndCount.fCount != that.fValue.fArrayAndCount.fCount) {
263 equal = FALSE;
264 break;
265 }
b75a7d8f 266 // Checks each element for equality.
374ca955
A
267 for (i=0; i<fValue.fArrayAndCount.fCount; ++i) {
268 if (fValue.fArrayAndCount.fArray[i] != that.fValue.fArrayAndCount.fArray[i]) {
269 equal = FALSE;
270 break;
271 }
272 }
273 break;
274 case kObject:
275 equal = objectEquals(fValue.fObject, that.fValue.fObject);
b75a7d8f
A
276 break;
277 }
374ca955
A
278
279 return equal;
b75a7d8f
A
280}
281
282// -------------------------------------
283
284Formattable::~Formattable()
285{
286 dispose();
287}
288
289// -------------------------------------
290
291void Formattable::dispose()
292{
293 // Deletes the data value if necessary.
294 switch (fType) {
295 case kString:
296 delete fValue.fString;
297 break;
298 case kArray:
299 delete[] fValue.fArrayAndCount.fArray;
300 break;
374ca955
A
301 case kObject:
302 delete fValue.fObject;
303 break;
304 default:
b75a7d8f
A
305 break;
306 }
307}
308
374ca955
A
309Formattable *
310Formattable::clone() const {
311 return new Formattable(*this);
312}
313
b75a7d8f
A
314// -------------------------------------
315// Gets the data type of this Formattable object.
316Formattable::Type
317Formattable::getType() const
318{
319 return fType;
320}
321
374ca955
A
322UBool
323Formattable::isNumeric() const {
324 switch (fType) {
325 case kDouble:
326 case kLong:
327 case kInt64:
328 return TRUE;
329 default:
330 return FALSE;
331 }
332}
333
334// -------------------------------------
335int32_t
336//Formattable::getLong(UErrorCode* status) const
337Formattable::getLong(UErrorCode& status) const
338{
339 if (U_FAILURE(status)) {
340 return 0;
341 }
342
343 switch (fType) {
344 case Formattable::kLong:
345 return (int32_t)fValue.fInt64;
346 case Formattable::kInt64:
347 if (fValue.fInt64 > INT32_MAX) {
348 status = U_INVALID_FORMAT_ERROR;
349 return INT32_MAX;
350 } else if (fValue.fInt64 < INT32_MIN) {
351 status = U_INVALID_FORMAT_ERROR;
352 return INT32_MIN;
353 } else {
354 return (int32_t)fValue.fInt64;
355 }
356 case Formattable::kDouble:
357 if (fValue.fDouble > INT32_MAX) {
358 status = U_INVALID_FORMAT_ERROR;
359 return INT32_MAX;
360 } else if (fValue.fDouble < INT32_MIN) {
361 status = U_INVALID_FORMAT_ERROR;
362 return INT32_MIN;
363 } else {
364 return (int32_t)fValue.fDouble; // loses fraction
365 }
366 case Formattable::kObject:
367 // TODO Later replace this with instanceof call
368 if (instanceOfMeasure(fValue.fObject)) {
369 return ((const Measure*) fValue.fObject)->
370 getNumber().getLong(status);
371 }
372 default:
373 status = U_INVALID_FORMAT_ERROR;
374 return 0;
375 }
376}
377
378// -------------------------------------
379int64_t
380Formattable::getInt64(UErrorCode& status) const
381{
382 if (U_FAILURE(status)) {
383 return 0;
384 }
385
386 switch (fType) {
387 case Formattable::kLong:
388 case Formattable::kInt64:
389 return fValue.fInt64;
390 case Formattable::kDouble:
391 if (fValue.fDouble > U_INT64_MAX) {
392 status = U_INVALID_FORMAT_ERROR;
393 return U_INT64_MAX;
394 } else if (fValue.fDouble < U_INT64_MIN) {
395 status = U_INVALID_FORMAT_ERROR;
396 return U_INT64_MIN;
397 } else {
398 return (int64_t)fValue.fDouble;
399 }
400 case Formattable::kObject:
401 // TODO Later replace this with instanceof call
402 if (instanceOfMeasure(fValue.fObject)) {
403 return ((const Measure*) fValue.fObject)->
404 getNumber().getInt64(status);
405 }
406 default:
407 status = U_INVALID_FORMAT_ERROR;
408 return 0;
409 }
410}
411
412// -------------------------------------
413double
414Formattable::getDouble(UErrorCode& status) const
415{
416 if (U_FAILURE(status)) {
417 return 0;
418 }
419
420 switch (fType) {
421 case Formattable::kLong:
422 case Formattable::kInt64: // loses precision
423 return (double)fValue.fInt64;
424 case Formattable::kDouble:
425 return fValue.fDouble;
426 case Formattable::kObject:
427 // TODO Later replace this with instanceof call
428 if (instanceOfMeasure(fValue.fObject)) {
429 return ((const Measure*) fValue.fObject)->
430 getNumber().getDouble(status);
431 }
432 default:
433 status = U_INVALID_FORMAT_ERROR;
434 return 0;
435 }
436}
437
438const UObject*
439Formattable::getObject() const {
440 return (fType == kObject) ? fValue.fObject : NULL;
441}
442
b75a7d8f
A
443// -------------------------------------
444// Sets the value to a double value d.
445
446void
447Formattable::setDouble(double d)
448{
449 dispose();
450 fType = kDouble;
451 fValue.fDouble = d;
452}
453
454// -------------------------------------
455// Sets the value to a long value l.
456
457void
458Formattable::setLong(int32_t l)
459{
460 dispose();
461 fType = kLong;
374ca955
A
462 fValue.fInt64 = l;
463}
464
465// -------------------------------------
466// Sets the value to an int64 value ll.
467
468void
469Formattable::setInt64(int64_t ll)
470{
471 dispose();
472 fType = kInt64;
473 fValue.fInt64 = ll;
b75a7d8f
A
474}
475
476// -------------------------------------
477// Sets the value to a Date instance d.
478
479void
480Formattable::setDate(UDate d)
481{
482 dispose();
483 fType = kDate;
484 fValue.fDate = d;
485}
486
487// -------------------------------------
488// Sets the value to a string value stringToCopy.
489
490void
491Formattable::setString(const UnicodeString& stringToCopy)
492{
493 dispose();
494 fType = kString;
495 fValue.fString = new UnicodeString(stringToCopy);
496}
497
498// -------------------------------------
499// Sets the value to an array of Formattable objects.
500
501void
502Formattable::setArray(const Formattable* array, int32_t count)
503{
504 dispose();
505 fType = kArray;
506 fValue.fArrayAndCount.fArray = createArrayCopy(array, count);
507 fValue.fArrayAndCount.fCount = count;
508}
509
510// -------------------------------------
511// Adopts the stringToAdopt value.
512
513void
514Formattable::adoptString(UnicodeString* stringToAdopt)
515{
516 dispose();
517 fType = kString;
518 fValue.fString = stringToAdopt;
519}
520
521// -------------------------------------
522// Adopts the array value and its count.
523
524void
525Formattable::adoptArray(Formattable* array, int32_t count)
526{
527 dispose();
528 fType = kArray;
529 fValue.fArrayAndCount.fArray = array;
530 fValue.fArrayAndCount.fCount = count;
531}
532
374ca955
A
533void
534Formattable::adoptObject(UObject* objectToAdopt) {
535 dispose();
536 fType = kObject;
537 fValue.fObject = objectToAdopt;
538}
539
540// -------------------------------------
541UnicodeString&
542Formattable::getString(UnicodeString& result, UErrorCode& status) const
543{
544 if (fType != kString) {
545 setError(status, U_INVALID_FORMAT_ERROR);
546 result.setToBogus();
547 } else {
548 result = *fValue.fString;
549 }
550 return result;
551}
552
553// -------------------------------------
554const UnicodeString&
555Formattable::getString(UErrorCode& status) const
556{
557 if (fType != kString) {
558 setError(status, U_INVALID_FORMAT_ERROR);
559 return *getBogus();
560 }
561 return *fValue.fString;
562}
563
564// -------------------------------------
565UnicodeString&
566Formattable::getString(UErrorCode& status)
567{
568 if (fType != kString) {
569 setError(status, U_INVALID_FORMAT_ERROR);
570 return *getBogus();
571 }
572 return *fValue.fString;
573}
574
575// -------------------------------------
576const Formattable*
577Formattable::getArray(int32_t& count, UErrorCode& status) const
578{
579 if (fType != kArray) {
580 setError(status, U_INVALID_FORMAT_ERROR);
581 count = 0;
582 return NULL;
583 }
584 count = fValue.fArrayAndCount.fCount;
585 return fValue.fArrayAndCount.fArray;
586}
587
588// -------------------------------------
589// Gets the bogus string, ensures mondo bogosity.
590
591UnicodeString*
592Formattable::getBogus() const
593{
594 return (UnicodeString*)&fBogus; /* cast away const :-( */
595}
596
b75a7d8f
A
597#if 0
598//----------------------------------------------------
599// console I/O
600//----------------------------------------------------
601#ifdef _DEBUG
602
603#if U_IOSTREAM_SOURCE >= 199711
604#include <iostream>
605using namespace std;
606#elif U_IOSTREAM_SOURCE >= 198506
607#include <iostream.h>
608#endif
609
610#include "unicode/datefmt.h"
611#include "unistrm.h"
612
613class FormattableStreamer /* not : public UObject because all methods are static */ {
614public:
615 static void streamOut(ostream& stream, const Formattable& obj);
616
617private:
618 FormattableStreamer() {} // private - forbid instantiation
619};
620
621// This is for debugging purposes only. This will send a displayable
622// form of the Formattable object to the output stream.
623
624void
625FormattableStreamer::streamOut(ostream& stream, const Formattable& obj)
626{
627 static DateFormat *defDateFormat = 0;
628
629 UnicodeString buffer;
630 switch(obj.getType()) {
631 case Formattable::kDate :
632 // Creates a DateFormat instance for formatting the
633 // Date instance.
634 if (defDateFormat == 0) {
635 defDateFormat = DateFormat::createInstance();
636 }
637 defDateFormat->format(obj.getDate(), buffer);
638 stream << buffer;
639 break;
640 case Formattable::kDouble :
641 // Output the double as is.
642 stream << obj.getDouble() << 'D';
643 break;
644 case Formattable::kLong :
645 // Output the double as is.
646 stream << obj.getLong() << 'L';
647 break;
648 case Formattable::kString:
649 // Output the double as is. Please see UnicodeString console
650 // I/O routine for more details.
651 stream << '"' << obj.getString(buffer) << '"';
652 break;
653 case Formattable::kArray:
654 int32_t i, count;
655 const Formattable* array;
656 array = obj.getArray(count);
657 stream << '[';
658 // Recursively calling the console I/O routine for each element in the array.
659 for (i=0; i<count; ++i) {
660 FormattableStreamer::streamOut(stream, array[i]);
661 stream << ( (i==(count-1)) ? "" : ", " );
662 }
663 stream << ']';
664 break;
665 default:
666 // Not a recognizable Formattable object.
667 stream << "INVALID_Formattable";
668 }
669 stream.flush();
670}
671#endif
672
673#endif
674
675U_NAMESPACE_END
676
677#endif /* #if !UCONFIG_NO_FORMATTING */
678
679//eof