1 /*
2 **********************************************************************
3 * Copyright (c) 2004-2014, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 **********************************************************************
6 * Author: Alan Liu
7 * Created: April 26, 2004
8 * Since: ICU 3.0
9 **********************************************************************
10 */
11 #include "utypeinfo.h" // for 'typeid' to work
12
13 #include "unicode/measunit.h"
14
15 #if !UCONFIG_NO_FORMATTING
16
17 #include "unicode/uenum.h"
18 #include "ustrenum.h"
19 #include "cstring.h"
20 #include "uassert.h"
21
22 #define LENGTHOF(array) (int32_t)(sizeof(array) / sizeof((array)[0]))
23
24 U_NAMESPACE_BEGIN
25
26 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MeasureUnit)
27
28 static const int32_t gOffsets[] = {
29 0,
30 1,
31 4,
32 10,
33 270,
34 278,
35 288,
36 292,
37 295,
38 298,
39 301,
40 303,
41 306
42 };
43
44 static const int32_t gIndexes[] = {
45 0,
46 1,
47 4,
48 10,
49 10,
50 18,
51 28,
52 32,
53 35,
54 38,
55 41,
56 43,
57 46
58 };
59
60 static const char * const gTypes[] = {
61 "acceleration",
62 "angle",
63 "area",
64 "currency",
65 "duration",
66 "length",
67 "mass",
68 "power",
69 "pressure",
70 "speed",
71 "temperature",
72 "volume"
73 };
74
75 static const char * const gSubTypes[] = {
76 "g-force",
77 "arc-minute",
78 "arc-second",
79 "degree",
80 "acre",
81 "hectare",
82 "square-foot",
83 "square-kilometer",
84 "square-meter",
85 "square-mile",
86 "ADP",
87 "AED",
88 "AFA",
89 "AFN",
90 "ALL",
91 "AMD",
92 "ANG",
93 "AOA",
94 "AON",
95 "AOR",
96 "ARA",
97 "ARP",
98 "ARS",
99 "ATS",
100 "AUD",
101 "AWG",
102 "AYM",
103 "AZM",
104 "AZN",
105 "BAD",
106 "BAM",
107 "BBD",
108 "BDT",
109 "BEC",
110 "BEF",
111 "BEL",
112 "BGL",
113 "BGN",
114 "BHD",
115 "BIF",
116 "BMD",
117 "BND",
118 "BOB",
119 "BOV",
120 "BRC",
121 "BRE",
122 "BRL",
123 "BRN",
124 "BRR",
125 "BSD",
126 "BTN",
127 "BWP",
128 "BYB",
129 "BYR",
130 "BZD",
131 "CAD",
132 "CDF",
133 "CHC",
134 "CHE",
135 "CHF",
136 "CHW",
137 "CLF",
138 "CLP",
139 "CNY",
140 "COP",
141 "COU",
142 "CRC",
143 "CSD",
144 "CSK",
145 "CUC",
146 "CUP",
147 "CVE",
148 "CYP",
149 "CZK",
150 "DDM",
151 "DEM",
152 "DJF",
153 "DKK",
154 "DOP",
155 "DZD",
156 "ECS",
157 "ECV",
158 "EEK",
159 "EGP",
160 "ERN",
161 "ESA",
162 "ESB",
163 "ESP",
164 "ETB",
165 "EUR",
166 "FIM",
167 "FJD",
168 "FKP",
169 "FRF",
170 "GBP",
171 "GEK",
172 "GEL",
173 "GHC",
174 "GHP",
175 "GHS",
176 "GIP",
177 "GMD",
178 "GNF",
179 "GQE",
180 "GRD",
181 "GTQ",
182 "GWP",
183 "GYD",
184 "HKD",
185 "HNL",
186 "HRD",
187 "HRK",
188 "HTG",
189 "HUF",
190 "IDR",
191 "IEP",
192 "ILS",
193 "INR",
194 "IQD",
195 "IRR",
196 "ISK",
197 "ITL",
198 "JMD",
199 "JOD",
200 "JPY",
201 "KES",
202 "KGS",
203 "KHR",
204 "KMF",
205 "KPW",
206 "KRW",
207 "KWD",
208 "KYD",
209 "KZT",
210 "LAK",
211 "LBP",
212 "LKR",
213 "LRD",
214 "LSL",
215 "LTL",
216 "LTT",
217 "LUC",
218 "LUF",
219 "LUL",
220 "LVL",
221 "LVR",
222 "LYD",
223 "MAD",
224 "MDL",
225 "MGA",
226 "MGF",
227 "MKD",
228 "MLF",
229 "MMK",
230 "MNT",
231 "MOP",
232 "MRO",
233 "MTL",
234 "MUR",
235 "MVR",
236 "MWK",
237 "MXN",
238 "MXV",
239 "MYR",
240 "MZM",
241 "MZN",
242 "NAD",
243 "NGN",
244 "NIO",
245 "NLG",
246 "NOK",
247 "NPR",
248 "NZD",
249 "OMR",
250 "PAB",
251 "PEI",
252 "PEN",
253 "PES",
254 "PGK",
255 "PHP",
256 "PKR",
257 "PLN",
258 "PLZ",
259 "PTE",
260 "PYG",
261 "QAR",
262 "ROL",
263 "RON",
264 "RSD",
265 "RUB",
266 "RUR",
267 "RWF",
268 "SAR",
269 "SBD",
270 "SCR",
271 "SDD",
272 "SDG",
273 "SEK",
274 "SGD",
275 "SHP",
276 "SIT",
277 "SKK",
278 "SLL",
279 "SOS",
280 "SRD",
281 "SRG",
282 "SSP",
283 "STD",
284 "SVC",
285 "SYP",
286 "SZL",
287 "THB",
288 "TJR",
289 "TJS",
290 "TMM",
291 "TMT",
292 "TND",
293 "TOP",
294 "TPE",
295 "TRL",
296 "TRY",
297 "TTD",
298 "TWD",
299 "TZS",
300 "UAH",
301 "UAK",
302 "UGX",
303 "USD",
304 "USN",
305 "USS",
306 "UYI",
307 "UYU",
308 "UZS",
309 "VEB",
310 "VEF",
311 "VND",
312 "VUV",
313 "WST",
314 "XAF",
315 "XAG",
316 "XAU",
317 "XBA",
318 "XBB",
319 "XBC",
320 "XBD",
321 "XCD",
322 "XDR",
323 "XEU",
324 "XOF",
325 "XPD",
326 "XPF",
327 "XPT",
328 "XSU",
329 "XTS",
330 "XUA",
331 "XXX",
332 "YDD",
333 "YER",
334 "YUM",
335 "YUN",
336 "ZAL",
337 "ZAR",
338 "ZMK",
339 "ZMW",
340 "ZRN",
341 "ZRZ",
342 "ZWD",
343 "ZWL",
344 "ZWN",
345 "ZWR",
346 "day",
347 "hour",
348 "millisecond",
349 "minute",
350 "month",
351 "second",
352 "week",
353 "year",
354 "centimeter",
355 "foot",
356 "inch",
357 "kilometer",
358 "light-year",
359 "meter",
360 "mile",
361 "millimeter",
362 "picometer",
363 "yard",
364 "gram",
365 "kilogram",
366 "ounce",
367 "pound",
368 "horsepower",
369 "kilowatt",
370 "watt",
371 "hectopascal",
372 "inch-hg",
373 "millibar",
374 "kilometer-per-hour",
375 "meter-per-second",
376 "mile-per-hour",
377 "celsius",
378 "fahrenheit",
379 "cubic-kilometer",
380 "cubic-mile",
381 "liter"
382 };
383
createGForce(UErrorCode & status)384 MeasureUnit *MeasureUnit::createGForce(UErrorCode &status) {
385 return MeasureUnit::create(0, 0, status);
386 }
387
createArcMinute(UErrorCode & status)388 MeasureUnit *MeasureUnit::createArcMinute(UErrorCode &status) {
389 return MeasureUnit::create(1, 0, status);
390 }
391
createArcSecond(UErrorCode & status)392 MeasureUnit *MeasureUnit::createArcSecond(UErrorCode &status) {
393 return MeasureUnit::create(1, 1, status);
394 }
395
createDegree(UErrorCode & status)396 MeasureUnit *MeasureUnit::createDegree(UErrorCode &status) {
397 return MeasureUnit::create(1, 2, status);
398 }
399
createAcre(UErrorCode & status)400 MeasureUnit *MeasureUnit::createAcre(UErrorCode &status) {
401 return MeasureUnit::create(2, 0, status);
402 }
403
createHectare(UErrorCode & status)404 MeasureUnit *MeasureUnit::createHectare(UErrorCode &status) {
405 return MeasureUnit::create(2, 1, status);
406 }
407
createSquareFoot(UErrorCode & status)408 MeasureUnit *MeasureUnit::createSquareFoot(UErrorCode &status) {
409 return MeasureUnit::create(2, 2, status);
410 }
411
createSquareKilometer(UErrorCode & status)412 MeasureUnit *MeasureUnit::createSquareKilometer(UErrorCode &status) {
413 return MeasureUnit::create(2, 3, status);
414 }
415
createSquareMeter(UErrorCode & status)416 MeasureUnit *MeasureUnit::createSquareMeter(UErrorCode &status) {
417 return MeasureUnit::create(2, 4, status);
418 }
419
createSquareMile(UErrorCode & status)420 MeasureUnit *MeasureUnit::createSquareMile(UErrorCode &status) {
421 return MeasureUnit::create(2, 5, status);
422 }
423
createDay(UErrorCode & status)424 MeasureUnit *MeasureUnit::createDay(UErrorCode &status) {
425 return MeasureUnit::create(4, 0, status);
426 }
427
createHour(UErrorCode & status)428 MeasureUnit *MeasureUnit::createHour(UErrorCode &status) {
429 return MeasureUnit::create(4, 1, status);
430 }
431
createMillisecond(UErrorCode & status)432 MeasureUnit *MeasureUnit::createMillisecond(UErrorCode &status) {
433 return MeasureUnit::create(4, 2, status);
434 }
435
createMinute(UErrorCode & status)436 MeasureUnit *MeasureUnit::createMinute(UErrorCode &status) {
437 return MeasureUnit::create(4, 3, status);
438 }
439
createMonth(UErrorCode & status)440 MeasureUnit *MeasureUnit::createMonth(UErrorCode &status) {
441 return MeasureUnit::create(4, 4, status);
442 }
443
createSecond(UErrorCode & status)444 MeasureUnit *MeasureUnit::createSecond(UErrorCode &status) {
445 return MeasureUnit::create(4, 5, status);
446 }
447
createWeek(UErrorCode & status)448 MeasureUnit *MeasureUnit::createWeek(UErrorCode &status) {
449 return MeasureUnit::create(4, 6, status);
450 }
451
createYear(UErrorCode & status)452 MeasureUnit *MeasureUnit::createYear(UErrorCode &status) {
453 return MeasureUnit::create(4, 7, status);
454 }
455
createCentimeter(UErrorCode & status)456 MeasureUnit *MeasureUnit::createCentimeter(UErrorCode &status) {
457 return MeasureUnit::create(5, 0, status);
458 }
459
createFoot(UErrorCode & status)460 MeasureUnit *MeasureUnit::createFoot(UErrorCode &status) {
461 return MeasureUnit::create(5, 1, status);
462 }
463
createInch(UErrorCode & status)464 MeasureUnit *MeasureUnit::createInch(UErrorCode &status) {
465 return MeasureUnit::create(5, 2, status);
466 }
467
createKilometer(UErrorCode & status)468 MeasureUnit *MeasureUnit::createKilometer(UErrorCode &status) {
469 return MeasureUnit::create(5, 3, status);
470 }
471
createLightYear(UErrorCode & status)472 MeasureUnit *MeasureUnit::createLightYear(UErrorCode &status) {
473 return MeasureUnit::create(5, 4, status);
474 }
475
createMeter(UErrorCode & status)476 MeasureUnit *MeasureUnit::createMeter(UErrorCode &status) {
477 return MeasureUnit::create(5, 5, status);
478 }
479
createMile(UErrorCode & status)480 MeasureUnit *MeasureUnit::createMile(UErrorCode &status) {
481 return MeasureUnit::create(5, 6, status);
482 }
483
createMillimeter(UErrorCode & status)484 MeasureUnit *MeasureUnit::createMillimeter(UErrorCode &status) {
485 return MeasureUnit::create(5, 7, status);
486 }
487
createPicometer(UErrorCode & status)488 MeasureUnit *MeasureUnit::createPicometer(UErrorCode &status) {
489 return MeasureUnit::create(5, 8, status);
490 }
491
createYard(UErrorCode & status)492 MeasureUnit *MeasureUnit::createYard(UErrorCode &status) {
493 return MeasureUnit::create(5, 9, status);
494 }
495
createGram(UErrorCode & status)496 MeasureUnit *MeasureUnit::createGram(UErrorCode &status) {
497 return MeasureUnit::create(6, 0, status);
498 }
499
createKilogram(UErrorCode & status)500 MeasureUnit *MeasureUnit::createKilogram(UErrorCode &status) {
501 return MeasureUnit::create(6, 1, status);
502 }
503
createOunce(UErrorCode & status)504 MeasureUnit *MeasureUnit::createOunce(UErrorCode &status) {
505 return MeasureUnit::create(6, 2, status);
506 }
507
createPound(UErrorCode & status)508 MeasureUnit *MeasureUnit::createPound(UErrorCode &status) {
509 return MeasureUnit::create(6, 3, status);
510 }
511
createHorsepower(UErrorCode & status)512 MeasureUnit *MeasureUnit::createHorsepower(UErrorCode &status) {
513 return MeasureUnit::create(7, 0, status);
514 }
515
createKilowatt(UErrorCode & status)516 MeasureUnit *MeasureUnit::createKilowatt(UErrorCode &status) {
517 return MeasureUnit::create(7, 1, status);
518 }
519
createWatt(UErrorCode & status)520 MeasureUnit *MeasureUnit::createWatt(UErrorCode &status) {
521 return MeasureUnit::create(7, 2, status);
522 }
523
createHectopascal(UErrorCode & status)524 MeasureUnit *MeasureUnit::createHectopascal(UErrorCode &status) {
525 return MeasureUnit::create(8, 0, status);
526 }
527
createInchHg(UErrorCode & status)528 MeasureUnit *MeasureUnit::createInchHg(UErrorCode &status) {
529 return MeasureUnit::create(8, 1, status);
530 }
531
createMillibar(UErrorCode & status)532 MeasureUnit *MeasureUnit::createMillibar(UErrorCode &status) {
533 return MeasureUnit::create(8, 2, status);
534 }
535
createKilometerPerHour(UErrorCode & status)536 MeasureUnit *MeasureUnit::createKilometerPerHour(UErrorCode &status) {
537 return MeasureUnit::create(9, 0, status);
538 }
539
createMeterPerSecond(UErrorCode & status)540 MeasureUnit *MeasureUnit::createMeterPerSecond(UErrorCode &status) {
541 return MeasureUnit::create(9, 1, status);
542 }
543
createMilePerHour(UErrorCode & status)544 MeasureUnit *MeasureUnit::createMilePerHour(UErrorCode &status) {
545 return MeasureUnit::create(9, 2, status);
546 }
547
createCelsius(UErrorCode & status)548 MeasureUnit *MeasureUnit::createCelsius(UErrorCode &status) {
549 return MeasureUnit::create(10, 0, status);
550 }
551
createFahrenheit(UErrorCode & status)552 MeasureUnit *MeasureUnit::createFahrenheit(UErrorCode &status) {
553 return MeasureUnit::create(10, 1, status);
554 }
555
createCubicKilometer(UErrorCode & status)556 MeasureUnit *MeasureUnit::createCubicKilometer(UErrorCode &status) {
557 return MeasureUnit::create(11, 0, status);
558 }
559
createCubicMile(UErrorCode & status)560 MeasureUnit *MeasureUnit::createCubicMile(UErrorCode &status) {
561 return MeasureUnit::create(11, 1, status);
562 }
563
createLiter(UErrorCode & status)564 MeasureUnit *MeasureUnit::createLiter(UErrorCode &status) {
565 return MeasureUnit::create(11, 2, status);
566 }
567
binarySearch(const char * const * array,int32_t start,int32_t end,const char * key)568 static int32_t binarySearch(
569 const char * const * array, int32_t start, int32_t end, const char * key) {
570 while (start < end) {
571 int32_t mid = (start + end) / 2;
572 int32_t cmp = uprv_strcmp(array[mid], key);
573 if (cmp < 0) {
574 start = mid + 1;
575 continue;
576 }
577 if (cmp == 0) {
578 return mid;
579 }
580 end = mid;
581 }
582 return -1;
583 }
584
MeasureUnit(const MeasureUnit & other)585 MeasureUnit::MeasureUnit(const MeasureUnit &other)
586 : fTypeId(other.fTypeId), fSubTypeId(other.fSubTypeId) {
587 uprv_strcpy(fCurrency, other.fCurrency);
588 }
589
operator =(const MeasureUnit & other)590 MeasureUnit &MeasureUnit::operator=(const MeasureUnit &other) {
591 if (this == &other) {
592 return *this;
593 }
594 fTypeId = other.fTypeId;
595 fSubTypeId = other.fSubTypeId;
596 uprv_strcpy(fCurrency, other.fCurrency);
597 return *this;
598 }
599
clone() const600 UObject *MeasureUnit::clone() const {
601 return new MeasureUnit(*this);
602 }
603
~MeasureUnit()604 MeasureUnit::~MeasureUnit() {
605 }
606
getType() const607 const char *MeasureUnit::getType() const {
608 return gTypes[fTypeId];
609 }
610
getSubtype() const611 const char *MeasureUnit::getSubtype() const {
612 return fCurrency[0] == 0 ? gSubTypes[getOffset()] : fCurrency;
613 }
614
operator ==(const UObject & other) const615 UBool MeasureUnit::operator==(const UObject& other) const {
616 if (this == &other) { // Same object, equal
617 return TRUE;
618 }
619 if (typeid(*this) != typeid(other)) { // Different types, not equal
620 return FALSE;
621 }
622 const MeasureUnit &rhs = static_cast<const MeasureUnit&>(other);
623 return (
624 fTypeId == rhs.fTypeId
625 && fSubTypeId == rhs.fSubTypeId
626 && uprv_strcmp(fCurrency, rhs.fCurrency) == 0);
627 }
628
getIndex() const629 int32_t MeasureUnit::getIndex() const {
630 return gIndexes[fTypeId] + fSubTypeId;
631 }
632
getAvailable(MeasureUnit * dest,int32_t destCapacity,UErrorCode & errorCode)633 int32_t MeasureUnit::getAvailable(
634 MeasureUnit *dest,
635 int32_t destCapacity,
636 UErrorCode &errorCode) {
637 if (U_FAILURE(errorCode)) {
638 return 0;
639 }
640 if (destCapacity < LENGTHOF(gSubTypes)) {
641 errorCode = U_BUFFER_OVERFLOW_ERROR;
642 return LENGTHOF(gSubTypes);
643 }
644 int32_t idx = 0;
645 for (int32_t typeIdx = 0; typeIdx < LENGTHOF(gTypes); ++typeIdx) {
646 int32_t len = gOffsets[typeIdx + 1] - gOffsets[typeIdx];
647 for (int32_t subTypeIdx = 0; subTypeIdx < len; ++subTypeIdx) {
648 dest[idx].setTo(typeIdx, subTypeIdx);
649 ++idx;
650 }
651 }
652 U_ASSERT(idx == LENGTHOF(gSubTypes));
653 return LENGTHOF(gSubTypes);
654 }
655
getAvailable(const char * type,MeasureUnit * dest,int32_t destCapacity,UErrorCode & errorCode)656 int32_t MeasureUnit::getAvailable(
657 const char *type,
658 MeasureUnit *dest,
659 int32_t destCapacity,
660 UErrorCode &errorCode) {
661 if (U_FAILURE(errorCode)) {
662 return 0;
663 }
664 int32_t typeIdx = binarySearch(gTypes, 0, LENGTHOF(gTypes), type);
665 if (typeIdx == -1) {
666 return 0;
667 }
668 int32_t len = gOffsets[typeIdx + 1] - gOffsets[typeIdx];
669 if (destCapacity < len) {
670 errorCode = U_BUFFER_OVERFLOW_ERROR;
671 return len;
672 }
673 for (int subTypeIdx = 0; subTypeIdx < len; ++subTypeIdx) {
674 dest[subTypeIdx].setTo(typeIdx, subTypeIdx);
675 }
676 return len;
677 }
678
getAvailableTypes(UErrorCode & errorCode)679 StringEnumeration* MeasureUnit::getAvailableTypes(UErrorCode &errorCode) {
680 UEnumeration *uenum = uenum_openCharStringsEnumeration(
681 gTypes, LENGTHOF(gTypes), &errorCode);
682 if (U_FAILURE(errorCode)) {
683 uenum_close(uenum);
684 return NULL;
685 }
686 StringEnumeration *result = new UStringEnumeration(uenum);
687 if (result == NULL) {
688 errorCode = U_MEMORY_ALLOCATION_ERROR;
689 uenum_close(uenum);
690 return NULL;
691 }
692 return result;
693 }
694
getIndexCount()695 int32_t MeasureUnit::getIndexCount() {
696 return gIndexes[LENGTHOF(gIndexes) - 1];
697 }
698
create(int typeId,int subTypeId,UErrorCode & status)699 MeasureUnit *MeasureUnit::create(int typeId, int subTypeId, UErrorCode &status) {
700 if (U_FAILURE(status)) {
701 return NULL;
702 }
703 MeasureUnit *result = new MeasureUnit(typeId, subTypeId);
704 if (result == NULL) {
705 status = U_MEMORY_ALLOCATION_ERROR;
706 }
707 return result;
708 }
709
initTime(const char * timeId)710 void MeasureUnit::initTime(const char *timeId) {
711 int32_t result = binarySearch(gTypes, 0, LENGTHOF(gTypes), "duration");
712 U_ASSERT(result != -1);
713 fTypeId = result;
714 result = binarySearch(gSubTypes, gOffsets[fTypeId], gOffsets[fTypeId + 1], timeId);
715 U_ASSERT(result != -1);
716 fSubTypeId = result - gOffsets[fTypeId];
717 }
718
initCurrency(const char * isoCurrency)719 void MeasureUnit::initCurrency(const char *isoCurrency) {
720 int32_t result = binarySearch(gTypes, 0, LENGTHOF(gTypes), "currency");
721 U_ASSERT(result != -1);
722 fTypeId = result;
723 result = binarySearch(
724 gSubTypes, gOffsets[fTypeId], gOffsets[fTypeId + 1], isoCurrency);
725 if (result != -1) {
726 fSubTypeId = result - gOffsets[fTypeId];
727 } else {
728 uprv_strncpy(fCurrency, isoCurrency, LENGTHOF(fCurrency));
729 }
730 }
731
setTo(int32_t typeId,int32_t subTypeId)732 void MeasureUnit::setTo(int32_t typeId, int32_t subTypeId) {
733 fTypeId = typeId;
734 fSubTypeId = subTypeId;
735 fCurrency[0] = 0;
736 }
737
getOffset() const738 int32_t MeasureUnit::getOffset() const {
739 return gOffsets[fTypeId] + fSubTypeId;
740 }
741
742 U_NAMESPACE_END
743
744 #endif /* !UNCONFIG_NO_FORMATTING */
745