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