12e5b6d6dSopenharmony_ci// © 2018 and later: Unicode, Inc. and others.
22e5b6d6dSopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html
32e5b6d6dSopenharmony_ci
42e5b6d6dSopenharmony_ci#include "unicode/utypes.h"
52e5b6d6dSopenharmony_ci
62e5b6d6dSopenharmony_ci#if !UCONFIG_NO_FORMATTING
72e5b6d6dSopenharmony_ci
82e5b6d6dSopenharmony_ci// Allow implicit conversion from char16_t* to UnicodeString for this file:
92e5b6d6dSopenharmony_ci// Helpful in toString methods and elsewhere.
102e5b6d6dSopenharmony_ci#define UNISTR_FROM_STRING_EXPLICIT
112e5b6d6dSopenharmony_ci
122e5b6d6dSopenharmony_ci#include "unicode/numberrangeformatter.h"
132e5b6d6dSopenharmony_ci#include "pluralranges.h"
142e5b6d6dSopenharmony_ci#include "uresimp.h"
152e5b6d6dSopenharmony_ci#include "charstr.h"
162e5b6d6dSopenharmony_ci#include "uassert.h"
172e5b6d6dSopenharmony_ci#include "util.h"
182e5b6d6dSopenharmony_ci#include "numrange_impl.h"
192e5b6d6dSopenharmony_ci
202e5b6d6dSopenharmony_ciU_NAMESPACE_BEGIN
212e5b6d6dSopenharmony_ci
222e5b6d6dSopenharmony_ci
232e5b6d6dSopenharmony_cinamespace {
242e5b6d6dSopenharmony_ci
252e5b6d6dSopenharmony_ciclass PluralRangesDataSink : public ResourceSink {
262e5b6d6dSopenharmony_ci  public:
272e5b6d6dSopenharmony_ci    PluralRangesDataSink(StandardPluralRanges& output) : fOutput(output) {}
282e5b6d6dSopenharmony_ci
292e5b6d6dSopenharmony_ci    void put(const char* /*key*/, ResourceValue& value, UBool /*noFallback*/, UErrorCode& status) U_OVERRIDE {
302e5b6d6dSopenharmony_ci        ResourceArray entriesArray = value.getArray(status);
312e5b6d6dSopenharmony_ci        if (U_FAILURE(status)) { return; }
322e5b6d6dSopenharmony_ci        fOutput.setCapacity(entriesArray.getSize(), status);
332e5b6d6dSopenharmony_ci        if (U_FAILURE(status)) { return; }
342e5b6d6dSopenharmony_ci        for (int i = 0; entriesArray.getValue(i, value); i++) {
352e5b6d6dSopenharmony_ci            ResourceArray pluralFormsArray = value.getArray(status);
362e5b6d6dSopenharmony_ci            if (U_FAILURE(status)) { return; }
372e5b6d6dSopenharmony_ci            if (pluralFormsArray.getSize() != 3) {
382e5b6d6dSopenharmony_ci                status = U_RESOURCE_TYPE_MISMATCH;
392e5b6d6dSopenharmony_ci                return;
402e5b6d6dSopenharmony_ci            }
412e5b6d6dSopenharmony_ci            pluralFormsArray.getValue(0, value);
422e5b6d6dSopenharmony_ci            StandardPlural::Form first = StandardPlural::fromString(value.getUnicodeString(status), status);
432e5b6d6dSopenharmony_ci            if (U_FAILURE(status)) { return; }
442e5b6d6dSopenharmony_ci            pluralFormsArray.getValue(1, value);
452e5b6d6dSopenharmony_ci            StandardPlural::Form second = StandardPlural::fromString(value.getUnicodeString(status), status);
462e5b6d6dSopenharmony_ci            if (U_FAILURE(status)) { return; }
472e5b6d6dSopenharmony_ci            pluralFormsArray.getValue(2, value);
482e5b6d6dSopenharmony_ci            StandardPlural::Form result = StandardPlural::fromString(value.getUnicodeString(status), status);
492e5b6d6dSopenharmony_ci            if (U_FAILURE(status)) { return; }
502e5b6d6dSopenharmony_ci            fOutput.addPluralRange(first, second, result);
512e5b6d6dSopenharmony_ci        }
522e5b6d6dSopenharmony_ci    }
532e5b6d6dSopenharmony_ci
542e5b6d6dSopenharmony_ci  private:
552e5b6d6dSopenharmony_ci    StandardPluralRanges& fOutput;
562e5b6d6dSopenharmony_ci};
572e5b6d6dSopenharmony_ci
582e5b6d6dSopenharmony_civoid getPluralRangesData(const Locale& locale, StandardPluralRanges& output, UErrorCode& status) {
592e5b6d6dSopenharmony_ci    LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "pluralRanges", &status));
602e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) { return; }
612e5b6d6dSopenharmony_ci
622e5b6d6dSopenharmony_ci    CharString dataPath;
632e5b6d6dSopenharmony_ci    dataPath.append("locales/", -1, status);
642e5b6d6dSopenharmony_ci    dataPath.append(locale.getLanguage(), -1, status);
652e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) { return; }
662e5b6d6dSopenharmony_ci    int32_t setLen;
672e5b6d6dSopenharmony_ci    // Not all languages are covered: fail gracefully
682e5b6d6dSopenharmony_ci    UErrorCode internalStatus = U_ZERO_ERROR;
692e5b6d6dSopenharmony_ci    const UChar* set = ures_getStringByKeyWithFallback(rb.getAlias(), dataPath.data(), &setLen, &internalStatus);
702e5b6d6dSopenharmony_ci    if (U_FAILURE(internalStatus)) { return; }
712e5b6d6dSopenharmony_ci
722e5b6d6dSopenharmony_ci    dataPath.clear();
732e5b6d6dSopenharmony_ci    dataPath.append("rules/", -1, status);
742e5b6d6dSopenharmony_ci    dataPath.appendInvariantChars(set, setLen, status);
752e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) { return; }
762e5b6d6dSopenharmony_ci    PluralRangesDataSink sink(output);
772e5b6d6dSopenharmony_ci    ures_getAllItemsWithFallback(rb.getAlias(), dataPath.data(), sink, status);
782e5b6d6dSopenharmony_ci}
792e5b6d6dSopenharmony_ci
802e5b6d6dSopenharmony_ci} // namespace
812e5b6d6dSopenharmony_ci
822e5b6d6dSopenharmony_ci
832e5b6d6dSopenharmony_ciStandardPluralRanges
842e5b6d6dSopenharmony_ciStandardPluralRanges::forLocale(const Locale& locale, UErrorCode& status) {
852e5b6d6dSopenharmony_ci    StandardPluralRanges result;
862e5b6d6dSopenharmony_ci    getPluralRangesData(locale, result, status);
872e5b6d6dSopenharmony_ci    return result;
882e5b6d6dSopenharmony_ci}
892e5b6d6dSopenharmony_ci
902e5b6d6dSopenharmony_ciStandardPluralRanges
912e5b6d6dSopenharmony_ciStandardPluralRanges::copy(UErrorCode& status) const {
922e5b6d6dSopenharmony_ci    StandardPluralRanges result;
932e5b6d6dSopenharmony_ci    if (fTriplesLen > result.fTriples.getCapacity()) {
942e5b6d6dSopenharmony_ci        if (result.fTriples.resize(fTriplesLen) == nullptr) {
952e5b6d6dSopenharmony_ci            status = U_MEMORY_ALLOCATION_ERROR;
962e5b6d6dSopenharmony_ci            return result;
972e5b6d6dSopenharmony_ci        }
982e5b6d6dSopenharmony_ci    }
992e5b6d6dSopenharmony_ci    uprv_memcpy(result.fTriples.getAlias(),
1002e5b6d6dSopenharmony_ci        fTriples.getAlias(),
1012e5b6d6dSopenharmony_ci        fTriplesLen * sizeof(fTriples[0]));
1022e5b6d6dSopenharmony_ci    result.fTriplesLen = fTriplesLen;
1032e5b6d6dSopenharmony_ci    return result;
1042e5b6d6dSopenharmony_ci}
1052e5b6d6dSopenharmony_ci
1062e5b6d6dSopenharmony_ciLocalPointer<StandardPluralRanges>
1072e5b6d6dSopenharmony_ciStandardPluralRanges::toPointer(UErrorCode& status) && noexcept {
1082e5b6d6dSopenharmony_ci    return LocalPointer<StandardPluralRanges>(new StandardPluralRanges(std::move(*this)), status);
1092e5b6d6dSopenharmony_ci}
1102e5b6d6dSopenharmony_ci
1112e5b6d6dSopenharmony_civoid StandardPluralRanges::addPluralRange(
1122e5b6d6dSopenharmony_ci        StandardPlural::Form first,
1132e5b6d6dSopenharmony_ci        StandardPlural::Form second,
1142e5b6d6dSopenharmony_ci        StandardPlural::Form result) {
1152e5b6d6dSopenharmony_ci    U_ASSERT(fTriplesLen < fTriples.getCapacity());
1162e5b6d6dSopenharmony_ci    fTriples[fTriplesLen] = {first, second, result};
1172e5b6d6dSopenharmony_ci    fTriplesLen++;
1182e5b6d6dSopenharmony_ci}
1192e5b6d6dSopenharmony_ci
1202e5b6d6dSopenharmony_civoid StandardPluralRanges::setCapacity(int32_t length, UErrorCode& status) {
1212e5b6d6dSopenharmony_ci    if (U_FAILURE(status)) { return; }
1222e5b6d6dSopenharmony_ci    if (length > fTriples.getCapacity()) {
1232e5b6d6dSopenharmony_ci        if (fTriples.resize(length, 0) == nullptr) {
1242e5b6d6dSopenharmony_ci            status = U_MEMORY_ALLOCATION_ERROR;
1252e5b6d6dSopenharmony_ci        }
1262e5b6d6dSopenharmony_ci    }
1272e5b6d6dSopenharmony_ci}
1282e5b6d6dSopenharmony_ci
1292e5b6d6dSopenharmony_ciStandardPlural::Form
1302e5b6d6dSopenharmony_ciStandardPluralRanges::resolve(StandardPlural::Form first, StandardPlural::Form second) const {
1312e5b6d6dSopenharmony_ci    for (int32_t i=0; i<fTriplesLen; i++) {
1322e5b6d6dSopenharmony_ci        const auto& triple = fTriples[i];
1332e5b6d6dSopenharmony_ci        if (triple.first == first && triple.second == second) {
1342e5b6d6dSopenharmony_ci            return triple.result;
1352e5b6d6dSopenharmony_ci        }
1362e5b6d6dSopenharmony_ci    }
1372e5b6d6dSopenharmony_ci    // Default fallback
1382e5b6d6dSopenharmony_ci    return StandardPlural::OTHER;
1392e5b6d6dSopenharmony_ci}
1402e5b6d6dSopenharmony_ci
1412e5b6d6dSopenharmony_ci
1422e5b6d6dSopenharmony_ciU_NAMESPACE_END
1432e5b6d6dSopenharmony_ci
1442e5b6d6dSopenharmony_ci#endif /* #if !UCONFIG_NO_FORMATTING */
145