1/* 2****************************************************************************** 3* Copyright (C) 2014, International Business Machines 4* Corporation and others. All Rights Reserved. 5****************************************************************************** 6* quantityformatter.cpp 7*/ 8#include "quantityformatter.h" 9#include "simplepatternformatter.h" 10#include "uassert.h" 11#include "unicode/unistr.h" 12#include "unicode/decimfmt.h" 13#include "cstring.h" 14#include "plurrule_impl.h" 15#include "unicode/plurrule.h" 16#include "charstr.h" 17#include "unicode/fmtable.h" 18#include "unicode/fieldpos.h" 19 20#define LENGTHOF(array) (int32_t)(sizeof(array) / sizeof((array)[0])) 21 22#if !UCONFIG_NO_FORMATTING 23 24U_NAMESPACE_BEGIN 25 26// other must always be first. 27static const char * const gPluralForms[] = { 28 "other", "zero", "one", "two", "few", "many"}; 29 30static int32_t getPluralIndex(const char *pluralForm) { 31 int32_t len = LENGTHOF(gPluralForms); 32 for (int32_t i = 0; i < len; ++i) { 33 if (uprv_strcmp(pluralForm, gPluralForms[i]) == 0) { 34 return i; 35 } 36 } 37 return -1; 38} 39 40QuantityFormatter::QuantityFormatter() { 41 for (int32_t i = 0; i < LENGTHOF(formatters); ++i) { 42 formatters[i] = NULL; 43 } 44} 45 46QuantityFormatter::QuantityFormatter(const QuantityFormatter &other) { 47 for (int32_t i = 0; i < LENGTHOF(formatters); ++i) { 48 if (other.formatters[i] == NULL) { 49 formatters[i] = NULL; 50 } else { 51 formatters[i] = new SimplePatternFormatter(*other.formatters[i]); 52 } 53 } 54} 55 56QuantityFormatter &QuantityFormatter::operator=( 57 const QuantityFormatter& other) { 58 if (this == &other) { 59 return *this; 60 } 61 for (int32_t i = 0; i < LENGTHOF(formatters); ++i) { 62 delete formatters[i]; 63 if (other.formatters[i] == NULL) { 64 formatters[i] = NULL; 65 } else { 66 formatters[i] = new SimplePatternFormatter(*other.formatters[i]); 67 } 68 } 69 return *this; 70} 71 72QuantityFormatter::~QuantityFormatter() { 73 for (int32_t i = 0; i < LENGTHOF(formatters); ++i) { 74 delete formatters[i]; 75 } 76} 77 78void QuantityFormatter::reset() { 79 for (int32_t i = 0; i < LENGTHOF(formatters); ++i) { 80 delete formatters[i]; 81 formatters[i] = NULL; 82 } 83} 84 85UBool QuantityFormatter::add( 86 const char *variant, 87 const UnicodeString &rawPattern, 88 UErrorCode &status) { 89 if (U_FAILURE(status)) { 90 return FALSE; 91 } 92 int32_t pluralIndex = getPluralIndex(variant); 93 if (pluralIndex == -1) { 94 status = U_ILLEGAL_ARGUMENT_ERROR; 95 return FALSE; 96 } 97 SimplePatternFormatter *newFmt = 98 new SimplePatternFormatter(rawPattern); 99 if (newFmt == NULL) { 100 status = U_MEMORY_ALLOCATION_ERROR; 101 return FALSE; 102 } 103 if (newFmt->getPlaceholderCount() > 1) { 104 delete newFmt; 105 status = U_ILLEGAL_ARGUMENT_ERROR; 106 return FALSE; 107 } 108 delete formatters[pluralIndex]; 109 formatters[pluralIndex] = newFmt; 110 return TRUE; 111} 112 113UBool QuantityFormatter::isValid() const { 114 return formatters[0] != NULL; 115} 116 117UnicodeString &QuantityFormatter::format( 118 const Formattable& quantity, 119 const NumberFormat &fmt, 120 const PluralRules &rules, 121 UnicodeString &appendTo, 122 FieldPosition &pos, 123 UErrorCode &status) const { 124 if (U_FAILURE(status)) { 125 return appendTo; 126 } 127 UnicodeString count; 128 const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt); 129 if (decFmt != NULL) { 130 FixedDecimal fd = decFmt->getFixedDecimal(quantity, status); 131 if (U_FAILURE(status)) { 132 return appendTo; 133 } 134 count = rules.select(fd); 135 } else { 136 if (quantity.getType() == Formattable::kDouble) { 137 count = rules.select(quantity.getDouble()); 138 } else if (quantity.getType() == Formattable::kLong) { 139 count = rules.select(quantity.getLong()); 140 } else if (quantity.getType() == Formattable::kInt64) { 141 count = rules.select((double) quantity.getInt64()); 142 } else { 143 status = U_ILLEGAL_ARGUMENT_ERROR; 144 return appendTo; 145 } 146 } 147 CharString buffer; 148 buffer.appendInvariantChars(count, status); 149 if (U_FAILURE(status)) { 150 return appendTo; 151 } 152 int32_t pluralIndex = getPluralIndex(buffer.data()); 153 if (pluralIndex == -1) { 154 pluralIndex = 0; 155 } 156 const SimplePatternFormatter *pattern = formatters[pluralIndex]; 157 if (pattern == NULL) { 158 pattern = formatters[0]; 159 } 160 if (pattern == NULL) { 161 status = U_INVALID_STATE_ERROR; 162 return appendTo; 163 } 164 UnicodeString formattedNumber; 165 FieldPosition fpos(pos.getField()); 166 fmt.format(quantity, formattedNumber, fpos, status); 167 const UnicodeString *params[1] = {&formattedNumber}; 168 int32_t offsets[1]; 169 pattern->format(params, LENGTHOF(params), appendTo, offsets, LENGTHOF(offsets), status); 170 if (offsets[0] != -1) { 171 if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) { 172 pos.setBeginIndex(fpos.getBeginIndex() + offsets[0]); 173 pos.setEndIndex(fpos.getEndIndex() + offsets[0]); 174 } 175 } 176 return appendTo; 177} 178 179U_NAMESPACE_END 180 181#endif /* #if !UCONFIG_NO_FORMATTING */ 182