quantityformatter.cpp revision 0b3ec0516c035ea443fdc334025048597c740be1
1fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius/*
2fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius******************************************************************************
3c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert* Copyright (C) 2014-2015, International Business Machines
4fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* Corporation and others.  All Rights Reserved.
5fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius******************************************************************************
6fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* quantityformatter.cpp
7fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius*/
88ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer
98ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer#include "unicode/utypes.h"
108ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer
118ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer#if !UCONFIG_NO_FORMATTING
128ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer
13fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "quantityformatter.h"
14fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "simplepatternformatter.h"
15fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "uassert.h"
16fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/unistr.h"
17fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/decimfmt.h"
18fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "cstring.h"
19fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/plurrule.h"
20fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "charstr.h"
21fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/fmtable.h"
22fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/fieldpos.h"
238ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer#include "resource.h"
240b3ec0516c035ea443fdc334025048597c740be1Markus Scherer#include "standardplural.h"
25c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert#include "visibledigits.h"
268ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer#include "uassert.h"
27fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
28fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusU_NAMESPACE_BEGIN
29fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
30fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusQuantityFormatter::QuantityFormatter() {
31f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
32fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        formatters[i] = NULL;
33fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
34fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
35fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
36fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusQuantityFormatter::QuantityFormatter(const QuantityFormatter &other) {
37f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
38fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if (other.formatters[i] == NULL) {
39fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            formatters[i] = NULL;
40fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        } else {
41fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            formatters[i] = new SimplePatternFormatter(*other.formatters[i]);
42fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
43fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
44fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
45fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
46fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusQuantityFormatter &QuantityFormatter::operator=(
47fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const QuantityFormatter& other) {
48fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (this == &other) {
49fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return *this;
50fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
51f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
52fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        delete formatters[i];
53fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if (other.formatters[i] == NULL) {
54fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            formatters[i] = NULL;
55fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        } else {
56fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            formatters[i] = new SimplePatternFormatter(*other.formatters[i]);
57fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
58fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
59fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return *this;
60fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
61fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
62fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusQuantityFormatter::~QuantityFormatter() {
63f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
64fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        delete formatters[i];
65fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
66fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
67fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
68fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusvoid QuantityFormatter::reset() {
69f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    for (int32_t i = 0; i < UPRV_LENGTHOF(formatters); ++i) {
70fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        delete formatters[i];
71fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        formatters[i] = NULL;
72fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
73fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
74fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
758ce198ebe2317b05a969826d0b629cb2d0b894a2Markus SchererUBool QuantityFormatter::addIfAbsent(
76fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        const char *variant,
778ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer        const UnicodeString *rawPattern,
788ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer        const ResourceValue *patternValue,
79fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        UErrorCode &status) {
800b3ec0516c035ea443fdc334025048597c740be1Markus Scherer    int32_t pluralIndex = StandardPlural::indexFromString(variant, status);
81fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
82fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return FALSE;
83fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
848ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer    if (formatters[pluralIndex] != NULL) {
858ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer        return TRUE;
868ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer    }
878ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer    const UnicodeString &pattern =
888ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer            rawPattern != NULL ? *rawPattern : patternValue->getUnicodeString(status);
898ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer    SimplePatternFormatter *newFmt = new SimplePatternFormatter(pattern);
90fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (newFmt == NULL) {
91fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        status = U_MEMORY_ALLOCATION_ERROR;
92fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return FALSE;
93fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
94fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (newFmt->getPlaceholderCount() > 1) {
95fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        delete newFmt;
96fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        status = U_ILLEGAL_ARGUMENT_ERROR;
97fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return FALSE;
98fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
99fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    formatters[pluralIndex] = newFmt;
100fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return TRUE;
101fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
102fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
103fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusUBool QuantityFormatter::isValid() const {
1040b3ec0516c035ea443fdc334025048597c740be1Markus Scherer    return formatters[StandardPlural::OTHER] != NULL;
105fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
106fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
107f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusconst SimplePatternFormatter *QuantityFormatter::getByVariant(
108f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        const char *variant) const {
1098ce198ebe2317b05a969826d0b629cb2d0b894a2Markus Scherer    U_ASSERT(isValid());
1100b3ec0516c035ea443fdc334025048597c740be1Markus Scherer    int32_t pluralIndex = StandardPlural::indexOrOtherIndexFromString(variant);
111f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    const SimplePatternFormatter *pattern = formatters[pluralIndex];
112f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    if (pattern == NULL) {
1130b3ec0516c035ea443fdc334025048597c740be1Markus Scherer        pattern = formatters[StandardPlural::OTHER];
114f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    }
115f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    return pattern;
116f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius}
117f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius
118fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusUnicodeString &QuantityFormatter::format(
119fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            const Formattable& quantity,
120fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            const NumberFormat &fmt,
121fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            const PluralRules &rules,
122fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            UnicodeString &appendTo,
123fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            FieldPosition &pos,
124fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            UErrorCode &status) const {
125fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
126fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return appendTo;
127fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
128fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    UnicodeString count;
129c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    VisibleDigitsWithExponent digits;
130fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt);
131fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (decFmt != NULL) {
132c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        decFmt->initVisibleDigitsWithExponent(quantity, digits, status);
133fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if (U_FAILURE(status)) {
134fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return appendTo;
135fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
136c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        count = rules.select(digits);
137fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else {
138fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if (quantity.getType() == Formattable::kDouble) {
139fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            count = rules.select(quantity.getDouble());
140fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        } else if (quantity.getType() == Formattable::kLong) {
141fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            count = rules.select(quantity.getLong());
142fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        } else if (quantity.getType() == Formattable::kInt64) {
143fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            count = rules.select((double) quantity.getInt64());
144fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        } else {
145fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            status = U_ILLEGAL_ARGUMENT_ERROR;
146fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return appendTo;
147fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
148fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
149fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    CharString buffer;
150fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    buffer.appendInvariantChars(count, status);
151fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (U_FAILURE(status)) {
152fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return appendTo;
153fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
154f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    const SimplePatternFormatter *pattern = getByVariant(buffer.data());
155fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (pattern == NULL) {
156fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        status = U_INVALID_STATE_ERROR;
157fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return appendTo;
158fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
159fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    UnicodeString formattedNumber;
160fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    FieldPosition fpos(pos.getField());
161c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    if (decFmt != NULL) {
162c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        decFmt->format(digits, formattedNumber, fpos, status);
163c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    } else {
164c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert        fmt.format(quantity, formattedNumber, fpos, status);
165c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert    }
166fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    const UnicodeString *params[1] = {&formattedNumber};
167fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t offsets[1];
1681b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    pattern->formatAndAppend(
1691b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            params,
1701b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            UPRV_LENGTHOF(params),
1711b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            appendTo,
1721b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            offsets,
1731b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            UPRV_LENGTHOF(offsets),
1741b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            status);
175fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (offsets[0] != -1) {
176fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) {
177fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            pos.setBeginIndex(fpos.getBeginIndex() + offsets[0]);
178fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            pos.setEndIndex(fpos.getEndIndex() + offsets[0]);
179fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
180fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
181fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return appendTo;
182fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
183fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
184fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusU_NAMESPACE_END
185fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
186fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#endif /* #if !UCONFIG_NO_FORMATTING */
187