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