11cb0ef41Sopenharmony_ci// © 2018 and later: Unicode, Inc. and others.
21cb0ef41Sopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html
31cb0ef41Sopenharmony_ci
41cb0ef41Sopenharmony_ci#include "unicode/utypes.h"
51cb0ef41Sopenharmony_ci
61cb0ef41Sopenharmony_ci#if !UCONFIG_NO_FORMATTING
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci// Allow implicit conversion from char16_t* to UnicodeString for this file:
91cb0ef41Sopenharmony_ci// Helpful in toString methods and elsewhere.
101cb0ef41Sopenharmony_ci#define UNISTR_FROM_STRING_EXPLICIT
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ci#include "unicode/numberrangeformatter.h"
131cb0ef41Sopenharmony_ci#include "pluralranges.h"
141cb0ef41Sopenharmony_ci#include "uresimp.h"
151cb0ef41Sopenharmony_ci#include "charstr.h"
161cb0ef41Sopenharmony_ci#include "uassert.h"
171cb0ef41Sopenharmony_ci#include "util.h"
181cb0ef41Sopenharmony_ci#include "numrange_impl.h"
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_ciU_NAMESPACE_BEGIN
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_cinamespace {
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ciclass PluralRangesDataSink : public ResourceSink {
261cb0ef41Sopenharmony_ci  public:
271cb0ef41Sopenharmony_ci    PluralRangesDataSink(StandardPluralRanges& output) : fOutput(output) {}
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ci    void put(const char* /*key*/, ResourceValue& value, UBool /*noFallback*/, UErrorCode& status) override {
301cb0ef41Sopenharmony_ci        ResourceArray entriesArray = value.getArray(status);
311cb0ef41Sopenharmony_ci        if (U_FAILURE(status)) { return; }
321cb0ef41Sopenharmony_ci        fOutput.setCapacity(entriesArray.getSize(), status);
331cb0ef41Sopenharmony_ci        if (U_FAILURE(status)) { return; }
341cb0ef41Sopenharmony_ci        for (int i = 0; entriesArray.getValue(i, value); i++) {
351cb0ef41Sopenharmony_ci            ResourceArray pluralFormsArray = value.getArray(status);
361cb0ef41Sopenharmony_ci            if (U_FAILURE(status)) { return; }
371cb0ef41Sopenharmony_ci            if (pluralFormsArray.getSize() != 3) {
381cb0ef41Sopenharmony_ci                status = U_RESOURCE_TYPE_MISMATCH;
391cb0ef41Sopenharmony_ci                return;
401cb0ef41Sopenharmony_ci            }
411cb0ef41Sopenharmony_ci            pluralFormsArray.getValue(0, value);
421cb0ef41Sopenharmony_ci            StandardPlural::Form first = StandardPlural::fromString(value.getUnicodeString(status), status);
431cb0ef41Sopenharmony_ci            if (U_FAILURE(status)) { return; }
441cb0ef41Sopenharmony_ci            pluralFormsArray.getValue(1, value);
451cb0ef41Sopenharmony_ci            StandardPlural::Form second = StandardPlural::fromString(value.getUnicodeString(status), status);
461cb0ef41Sopenharmony_ci            if (U_FAILURE(status)) { return; }
471cb0ef41Sopenharmony_ci            pluralFormsArray.getValue(2, value);
481cb0ef41Sopenharmony_ci            StandardPlural::Form result = StandardPlural::fromString(value.getUnicodeString(status), status);
491cb0ef41Sopenharmony_ci            if (U_FAILURE(status)) { return; }
501cb0ef41Sopenharmony_ci            fOutput.addPluralRange(first, second, result);
511cb0ef41Sopenharmony_ci        }
521cb0ef41Sopenharmony_ci    }
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_ci  private:
551cb0ef41Sopenharmony_ci    StandardPluralRanges& fOutput;
561cb0ef41Sopenharmony_ci};
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_civoid getPluralRangesData(const Locale& locale, StandardPluralRanges& output, UErrorCode& status) {
591cb0ef41Sopenharmony_ci    LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "pluralRanges", &status));
601cb0ef41Sopenharmony_ci    if (U_FAILURE(status)) { return; }
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci    CharString dataPath;
631cb0ef41Sopenharmony_ci    dataPath.append("locales/", -1, status);
641cb0ef41Sopenharmony_ci    dataPath.append(locale.getLanguage(), -1, status);
651cb0ef41Sopenharmony_ci    if (U_FAILURE(status)) { return; }
661cb0ef41Sopenharmony_ci    int32_t setLen;
671cb0ef41Sopenharmony_ci    // Not all languages are covered: fail gracefully
681cb0ef41Sopenharmony_ci    UErrorCode internalStatus = U_ZERO_ERROR;
691cb0ef41Sopenharmony_ci    const char16_t* set = ures_getStringByKeyWithFallback(rb.getAlias(), dataPath.data(), &setLen, &internalStatus);
701cb0ef41Sopenharmony_ci    if (U_FAILURE(internalStatus)) { return; }
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci    dataPath.clear();
731cb0ef41Sopenharmony_ci    dataPath.append("rules/", -1, status);
741cb0ef41Sopenharmony_ci    dataPath.appendInvariantChars(set, setLen, status);
751cb0ef41Sopenharmony_ci    if (U_FAILURE(status)) { return; }
761cb0ef41Sopenharmony_ci    PluralRangesDataSink sink(output);
771cb0ef41Sopenharmony_ci    ures_getAllItemsWithFallback(rb.getAlias(), dataPath.data(), sink, status);
781cb0ef41Sopenharmony_ci}
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_ci} // namespace
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ciStandardPluralRanges
841cb0ef41Sopenharmony_ciStandardPluralRanges::forLocale(const Locale& locale, UErrorCode& status) {
851cb0ef41Sopenharmony_ci    StandardPluralRanges result;
861cb0ef41Sopenharmony_ci    getPluralRangesData(locale, result, status);
871cb0ef41Sopenharmony_ci    return result;
881cb0ef41Sopenharmony_ci}
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ciStandardPluralRanges
911cb0ef41Sopenharmony_ciStandardPluralRanges::copy(UErrorCode& status) const {
921cb0ef41Sopenharmony_ci    StandardPluralRanges result;
931cb0ef41Sopenharmony_ci    if (fTriplesLen > result.fTriples.getCapacity()) {
941cb0ef41Sopenharmony_ci        if (result.fTriples.resize(fTriplesLen) == nullptr) {
951cb0ef41Sopenharmony_ci            status = U_MEMORY_ALLOCATION_ERROR;
961cb0ef41Sopenharmony_ci            return result;
971cb0ef41Sopenharmony_ci        }
981cb0ef41Sopenharmony_ci    }
991cb0ef41Sopenharmony_ci    uprv_memcpy(result.fTriples.getAlias(),
1001cb0ef41Sopenharmony_ci        fTriples.getAlias(),
1011cb0ef41Sopenharmony_ci        fTriplesLen * sizeof(fTriples[0]));
1021cb0ef41Sopenharmony_ci    result.fTriplesLen = fTriplesLen;
1031cb0ef41Sopenharmony_ci    return result;
1041cb0ef41Sopenharmony_ci}
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ciLocalPointer<StandardPluralRanges>
1071cb0ef41Sopenharmony_ciStandardPluralRanges::toPointer(UErrorCode& status) && noexcept {
1081cb0ef41Sopenharmony_ci    return LocalPointer<StandardPluralRanges>(new StandardPluralRanges(std::move(*this)), status);
1091cb0ef41Sopenharmony_ci}
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_civoid StandardPluralRanges::addPluralRange(
1121cb0ef41Sopenharmony_ci        StandardPlural::Form first,
1131cb0ef41Sopenharmony_ci        StandardPlural::Form second,
1141cb0ef41Sopenharmony_ci        StandardPlural::Form result) {
1151cb0ef41Sopenharmony_ci    U_ASSERT(fTriplesLen < fTriples.getCapacity());
1161cb0ef41Sopenharmony_ci    fTriples[fTriplesLen] = {first, second, result};
1171cb0ef41Sopenharmony_ci    fTriplesLen++;
1181cb0ef41Sopenharmony_ci}
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_civoid StandardPluralRanges::setCapacity(int32_t length, UErrorCode& status) {
1211cb0ef41Sopenharmony_ci    if (U_FAILURE(status)) { return; }
1221cb0ef41Sopenharmony_ci    if (length > fTriples.getCapacity()) {
1231cb0ef41Sopenharmony_ci        if (fTriples.resize(length, 0) == nullptr) {
1241cb0ef41Sopenharmony_ci            status = U_MEMORY_ALLOCATION_ERROR;
1251cb0ef41Sopenharmony_ci        }
1261cb0ef41Sopenharmony_ci    }
1271cb0ef41Sopenharmony_ci}
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ciStandardPlural::Form
1301cb0ef41Sopenharmony_ciStandardPluralRanges::resolve(StandardPlural::Form first, StandardPlural::Form second) const {
1311cb0ef41Sopenharmony_ci    for (int32_t i=0; i<fTriplesLen; i++) {
1321cb0ef41Sopenharmony_ci        const auto& triple = fTriples[i];
1331cb0ef41Sopenharmony_ci        if (triple.first == first && triple.second == second) {
1341cb0ef41Sopenharmony_ci            return triple.result;
1351cb0ef41Sopenharmony_ci        }
1361cb0ef41Sopenharmony_ci    }
1371cb0ef41Sopenharmony_ci    // Default fallback
1381cb0ef41Sopenharmony_ci    return StandardPlural::OTHER;
1391cb0ef41Sopenharmony_ci}
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_ciU_NAMESPACE_END
1431cb0ef41Sopenharmony_ci
1441cb0ef41Sopenharmony_ci#endif /* #if !UCONFIG_NO_FORMATTING */
145