"Fossies" - the Fresh Open Source Software Archive

Member "icu/source/common/localematcher.cpp" (22 Apr 2020, 29368 Bytes) of package /linux/misc/icu4c-67_1-src.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "localematcher.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes reports: 67rc_vs_67_1 or 66_1_vs_67_1.

    1 // © 2019 and later: Unicode, Inc. and others.
    2 // License & terms of use: http://www.unicode.org/copyright.html#License
    3 
    4 // localematcher.cpp
    5 // created: 2019may08 Markus W. Scherer
    6 
    7 #ifndef __LOCMATCHER_H__
    8 #define __LOCMATCHER_H__
    9 
   10 #include "unicode/utypes.h"
   11 #include "unicode/localebuilder.h"
   12 #include "unicode/localematcher.h"
   13 #include "unicode/locid.h"
   14 #include "unicode/stringpiece.h"
   15 #include "unicode/uloc.h"
   16 #include "unicode/uobject.h"
   17 #include "cstring.h"
   18 #include "localeprioritylist.h"
   19 #include "loclikelysubtags.h"
   20 #include "locdistance.h"
   21 #include "lsr.h"
   22 #include "uassert.h"
   23 #include "uhash.h"
   24 #include "ustr_imp.h"
   25 #include "uvector.h"
   26 
   27 #define UND_LSR LSR("und", "", "", LSR::EXPLICIT_LSR)
   28 
   29 /**
   30  * Indicator for the lifetime of desired-locale objects passed into the LocaleMatcher.
   31  *
   32  * @draft ICU 65
   33  */
   34 enum ULocMatchLifetime {
   35     /**
   36      * Locale objects are temporary.
   37      * The matcher will make a copy of a locale that will be used beyond one function call.
   38      *
   39      * @draft ICU 65
   40      */
   41     ULOCMATCH_TEMPORARY_LOCALES,
   42     /**
   43      * Locale objects are stored at least as long as the matcher is used.
   44      * The matcher will keep only a pointer to a locale that will be used beyond one function call,
   45      * avoiding a copy.
   46      *
   47      * @draft ICU 65
   48      */
   49     ULOCMATCH_STORED_LOCALES  // TODO: permanent? cached? clone?
   50 };
   51 #ifndef U_IN_DOXYGEN
   52 typedef enum ULocMatchLifetime ULocMatchLifetime;
   53 #endif
   54 
   55 U_NAMESPACE_BEGIN
   56 
   57 LocaleMatcher::Result::Result(LocaleMatcher::Result &&src) U_NOEXCEPT :
   58         desiredLocale(src.desiredLocale),
   59         supportedLocale(src.supportedLocale),
   60         desiredIndex(src.desiredIndex),
   61         supportedIndex(src.supportedIndex),
   62         desiredIsOwned(src.desiredIsOwned) {
   63     if (desiredIsOwned) {
   64         src.desiredLocale = nullptr;
   65         src.desiredIndex = -1;
   66         src.desiredIsOwned = FALSE;
   67     }
   68 }
   69 
   70 LocaleMatcher::Result::~Result() {
   71     if (desiredIsOwned) {
   72         delete desiredLocale;
   73     }
   74 }
   75 
   76 LocaleMatcher::Result &LocaleMatcher::Result::operator=(LocaleMatcher::Result &&src) U_NOEXCEPT {
   77     this->~Result();
   78 
   79     desiredLocale = src.desiredLocale;
   80     supportedLocale = src.supportedLocale;
   81     desiredIndex = src.desiredIndex;
   82     supportedIndex = src.supportedIndex;
   83     desiredIsOwned = src.desiredIsOwned;
   84 
   85     if (desiredIsOwned) {
   86         src.desiredLocale = nullptr;
   87         src.desiredIndex = -1;
   88         src.desiredIsOwned = FALSE;
   89     }
   90     return *this;
   91 }
   92 
   93 Locale LocaleMatcher::Result::makeResolvedLocale(UErrorCode &errorCode) const {
   94     if (U_FAILURE(errorCode) || supportedLocale == nullptr) {
   95         return Locale::getRoot();
   96     }
   97     const Locale *bestDesired = getDesiredLocale();
   98     if (bestDesired == nullptr || *supportedLocale == *bestDesired) {
   99         return *supportedLocale;
  100     }
  101     LocaleBuilder b;
  102     b.setLocale(*supportedLocale);
  103 
  104     // Copy the region from bestDesired, if there is one.
  105     const char *region = bestDesired->getCountry();
  106     if (*region != 0) {
  107         b.setRegion(region);
  108     }
  109 
  110     // Copy the variants from bestDesired, if there are any.
  111     // Note that this will override any supportedLocale variants.
  112     // For example, "sco-ulster-fonipa" + "...-fonupa" => "sco-fonupa" (replacing ulster).
  113     const char *variants = bestDesired->getVariant();
  114     if (*variants != 0) {
  115         b.setVariant(variants);
  116     }
  117 
  118     // Copy the extensions from bestDesired, if there are any.
  119     // C++ note: The following note, copied from Java, may not be true,
  120     // as long as C++ copies by legacy ICU keyword, not by extension singleton.
  121     // Note that this will override any supportedLocale extensions.
  122     // For example, "th-u-nu-latn-ca-buddhist" + "...-u-nu-native" => "th-u-nu-native"
  123     // (replacing calendar).
  124     b.copyExtensionsFrom(*bestDesired, errorCode);
  125     return b.build(errorCode);
  126 }
  127 
  128 LocaleMatcher::Builder::Builder(LocaleMatcher::Builder &&src) U_NOEXCEPT :
  129         errorCode_(src.errorCode_),
  130         supportedLocales_(src.supportedLocales_),
  131         thresholdDistance_(src.thresholdDistance_),
  132         demotion_(src.demotion_),
  133         defaultLocale_(src.defaultLocale_),
  134         favor_(src.favor_),
  135         direction_(src.direction_) {
  136     src.supportedLocales_ = nullptr;
  137     src.defaultLocale_ = nullptr;
  138 }
  139 
  140 LocaleMatcher::Builder::~Builder() {
  141     delete supportedLocales_;
  142     delete defaultLocale_;
  143 }
  144 
  145 LocaleMatcher::Builder &LocaleMatcher::Builder::operator=(LocaleMatcher::Builder &&src) U_NOEXCEPT {
  146     this->~Builder();
  147 
  148     errorCode_ = src.errorCode_;
  149     supportedLocales_ = src.supportedLocales_;
  150     thresholdDistance_ = src.thresholdDistance_;
  151     demotion_ = src.demotion_;
  152     defaultLocale_ = src.defaultLocale_;
  153     favor_ = src.favor_;
  154     direction_ = src.direction_;
  155 
  156     src.supportedLocales_ = nullptr;
  157     src.defaultLocale_ = nullptr;
  158     return *this;
  159 }
  160 
  161 void LocaleMatcher::Builder::clearSupportedLocales() {
  162     if (supportedLocales_ != nullptr) {
  163         supportedLocales_->removeAllElements();
  164     }
  165 }
  166 
  167 bool LocaleMatcher::Builder::ensureSupportedLocaleVector() {
  168     if (U_FAILURE(errorCode_)) { return false; }
  169     if (supportedLocales_ != nullptr) { return true; }
  170     supportedLocales_ = new UVector(uprv_deleteUObject, nullptr, errorCode_);
  171     if (U_FAILURE(errorCode_)) { return false; }
  172     if (supportedLocales_ == nullptr) {
  173         errorCode_ = U_MEMORY_ALLOCATION_ERROR;
  174         return false;
  175     }
  176     return true;
  177 }
  178 
  179 LocaleMatcher::Builder &LocaleMatcher::Builder::setSupportedLocalesFromListString(
  180         StringPiece locales) {
  181     LocalePriorityList list(locales, errorCode_);
  182     if (U_FAILURE(errorCode_)) { return *this; }
  183     clearSupportedLocales();
  184     if (!ensureSupportedLocaleVector()) { return *this; }
  185     int32_t length = list.getLengthIncludingRemoved();
  186     for (int32_t i = 0; i < length; ++i) {
  187         Locale *locale = list.orphanLocaleAt(i);
  188         if (locale == nullptr) { continue; }
  189         supportedLocales_->addElement(locale, errorCode_);
  190         if (U_FAILURE(errorCode_)) {
  191             delete locale;
  192             break;
  193         }
  194     }
  195     return *this;
  196 }
  197 
  198 LocaleMatcher::Builder &LocaleMatcher::Builder::setSupportedLocales(Locale::Iterator &locales) {
  199     if (U_FAILURE(errorCode_)) { return *this; }
  200     clearSupportedLocales();
  201     if (!ensureSupportedLocaleVector()) { return *this; }
  202     while (locales.hasNext()) {
  203         const Locale &locale = locales.next();
  204         Locale *clone = locale.clone();
  205         if (clone == nullptr) {
  206             errorCode_ = U_MEMORY_ALLOCATION_ERROR;
  207             break;
  208         }
  209         supportedLocales_->addElement(clone, errorCode_);
  210         if (U_FAILURE(errorCode_)) {
  211             delete clone;
  212             break;
  213         }
  214     }
  215     return *this;
  216 }
  217 
  218 LocaleMatcher::Builder &LocaleMatcher::Builder::addSupportedLocale(const Locale &locale) {
  219     if (!ensureSupportedLocaleVector()) { return *this; }
  220     Locale *clone = locale.clone();
  221     if (clone == nullptr) {
  222         errorCode_ = U_MEMORY_ALLOCATION_ERROR;
  223         return *this;
  224     }
  225     supportedLocales_->addElement(clone, errorCode_);
  226     if (U_FAILURE(errorCode_)) {
  227         delete clone;
  228     }
  229     return *this;
  230 }
  231 
  232 LocaleMatcher::Builder &LocaleMatcher::Builder::setDefaultLocale(const Locale *defaultLocale) {
  233     if (U_FAILURE(errorCode_)) { return *this; }
  234     Locale *clone = nullptr;
  235     if (defaultLocale != nullptr) {
  236         clone = defaultLocale->clone();
  237         if (clone == nullptr) {
  238             errorCode_ = U_MEMORY_ALLOCATION_ERROR;
  239             return *this;
  240         }
  241     }
  242     delete defaultLocale_;
  243     defaultLocale_ = clone;
  244     return *this;
  245 }
  246 
  247 LocaleMatcher::Builder &LocaleMatcher::Builder::setFavorSubtag(ULocMatchFavorSubtag subtag) {
  248     if (U_FAILURE(errorCode_)) { return *this; }
  249     favor_ = subtag;
  250     return *this;
  251 }
  252 
  253 LocaleMatcher::Builder &LocaleMatcher::Builder::setDemotionPerDesiredLocale(ULocMatchDemotion demotion) {
  254     if (U_FAILURE(errorCode_)) { return *this; }
  255     demotion_ = demotion;
  256     return *this;
  257 }
  258 
  259 #if 0
  260 /**
  261  * <i>Internal only!</i>
  262  *
  263  * @param thresholdDistance the thresholdDistance to set, with -1 = default
  264  * @return this Builder object
  265  * @internal
  266  * @deprecated This API is ICU internal only.
  267  */
  268 @Deprecated
  269 LocaleMatcher::Builder &LocaleMatcher::Builder::internalSetThresholdDistance(int32_t thresholdDistance) {
  270     if (U_FAILURE(errorCode_)) { return *this; }
  271     if (thresholdDistance > 100) {
  272         thresholdDistance = 100;
  273     }
  274     thresholdDistance_ = thresholdDistance;
  275     return *this;
  276 }
  277 #endif
  278 
  279 UBool LocaleMatcher::Builder::copyErrorTo(UErrorCode &outErrorCode) const {
  280     if (U_FAILURE(outErrorCode)) { return TRUE; }
  281     if (U_SUCCESS(errorCode_)) { return FALSE; }
  282     outErrorCode = errorCode_;
  283     return TRUE;
  284 }
  285 
  286 LocaleMatcher LocaleMatcher::Builder::build(UErrorCode &errorCode) const {
  287     if (U_SUCCESS(errorCode) && U_FAILURE(errorCode_)) {
  288         errorCode = errorCode_;
  289     }
  290     return LocaleMatcher(*this, errorCode);
  291 }
  292 
  293 namespace {
  294 
  295 LSR getMaximalLsrOrUnd(const XLikelySubtags &likelySubtags, const Locale &locale,
  296                        UErrorCode &errorCode) {
  297     if (U_FAILURE(errorCode) || locale.isBogus() || *locale.getName() == 0 /* "und" */) {
  298         return UND_LSR;
  299     } else {
  300         return likelySubtags.makeMaximizedLsrFrom(locale, errorCode);
  301     }
  302 }
  303 
  304 int32_t hashLSR(const UHashTok token) {
  305     const LSR *lsr = static_cast<const LSR *>(token.pointer);
  306     return lsr->hashCode;
  307 }
  308 
  309 UBool compareLSRs(const UHashTok t1, const UHashTok t2) {
  310     const LSR *lsr1 = static_cast<const LSR *>(t1.pointer);
  311     const LSR *lsr2 = static_cast<const LSR *>(t2.pointer);
  312     return *lsr1 == *lsr2;
  313 }
  314 
  315 }  // namespace
  316 
  317 int32_t LocaleMatcher::putIfAbsent(const LSR &lsr, int32_t i, int32_t suppLength,
  318                                    UErrorCode &errorCode) {
  319     if (U_FAILURE(errorCode)) { return suppLength; }
  320     int32_t index = uhash_geti(supportedLsrToIndex, &lsr);
  321     if (index == 0) {
  322         uhash_puti(supportedLsrToIndex, const_cast<LSR *>(&lsr), i + 1, &errorCode);
  323         if (U_SUCCESS(errorCode)) {
  324             supportedLSRs[suppLength] = &lsr;
  325             supportedIndexes[suppLength++] = i;
  326         }
  327     }
  328     return suppLength;
  329 }
  330 
  331 LocaleMatcher::LocaleMatcher(const Builder &builder, UErrorCode &errorCode) :
  332         likelySubtags(*XLikelySubtags::getSingleton(errorCode)),
  333         localeDistance(*LocaleDistance::getSingleton(errorCode)),
  334         thresholdDistance(builder.thresholdDistance_),
  335         demotionPerDesiredLocale(0),
  336         favorSubtag(builder.favor_),
  337         direction(builder.direction_),
  338         supportedLocales(nullptr), lsrs(nullptr), supportedLocalesLength(0),
  339         supportedLsrToIndex(nullptr),
  340         supportedLSRs(nullptr), supportedIndexes(nullptr), supportedLSRsLength(0),
  341         ownedDefaultLocale(nullptr), defaultLocale(nullptr) {
  342     if (U_FAILURE(errorCode)) { return; }
  343     if (thresholdDistance < 0) {
  344         thresholdDistance = localeDistance.getDefaultScriptDistance();
  345     }
  346     const Locale *def = builder.defaultLocale_;
  347     LSR builderDefaultLSR;
  348     const LSR *defLSR = nullptr;
  349     if (def != nullptr) {
  350         ownedDefaultLocale = def->clone();
  351         if (ownedDefaultLocale == nullptr) {
  352             errorCode = U_MEMORY_ALLOCATION_ERROR;
  353             return;
  354         }
  355         def = ownedDefaultLocale;
  356         builderDefaultLSR = getMaximalLsrOrUnd(likelySubtags, *def, errorCode);
  357         if (U_FAILURE(errorCode)) { return; }
  358         defLSR = &builderDefaultLSR;
  359     }
  360     supportedLocalesLength = builder.supportedLocales_ != nullptr ?
  361         builder.supportedLocales_->size() : 0;
  362     if (supportedLocalesLength > 0) {
  363         // Store the supported locales in input order,
  364         // so that when different types are used (e.g., language tag strings)
  365         // we can return those by parallel index.
  366         supportedLocales = static_cast<const Locale **>(
  367             uprv_malloc(supportedLocalesLength * sizeof(const Locale *)));
  368         // Supported LRSs in input order.
  369         // In C++, we store these permanently to simplify ownership management
  370         // in the hash tables. Duplicate LSRs (if any) are unused overhead.
  371         lsrs = new LSR[supportedLocalesLength];
  372         if (supportedLocales == nullptr || lsrs == nullptr) {
  373             errorCode = U_MEMORY_ALLOCATION_ERROR;
  374             return;
  375         }
  376         // If the constructor fails partway, we need null pointers for destructibility.
  377         uprv_memset(supportedLocales, 0, supportedLocalesLength * sizeof(const Locale *));
  378         for (int32_t i = 0; i < supportedLocalesLength; ++i) {
  379             const Locale &locale = *static_cast<Locale *>(builder.supportedLocales_->elementAt(i));
  380             supportedLocales[i] = locale.clone();
  381             if (supportedLocales[i] == nullptr) {
  382                 errorCode = U_MEMORY_ALLOCATION_ERROR;
  383                 return;
  384             }
  385             const Locale &supportedLocale = *supportedLocales[i];
  386             LSR &lsr = lsrs[i] = getMaximalLsrOrUnd(likelySubtags, supportedLocale, errorCode);
  387             lsr.setHashCode();
  388             if (U_FAILURE(errorCode)) { return; }
  389         }
  390 
  391         // We need an unordered map from LSR to first supported locale with that LSR,
  392         // and an ordered list of (LSR, supported index) for
  393         // the supported locales in the following order:
  394         // 1. Default locale, if it is supported.
  395         // 2. Priority locales (aka "paradigm locales") in builder order.
  396         // 3. Remaining locales in builder order.
  397         supportedLsrToIndex = uhash_openSize(hashLSR, compareLSRs, uhash_compareLong,
  398                                              supportedLocalesLength, &errorCode);
  399         if (U_FAILURE(errorCode)) { return; }
  400         supportedLSRs = static_cast<const LSR **>(
  401             uprv_malloc(supportedLocalesLength * sizeof(const LSR *)));
  402         supportedIndexes = static_cast<int32_t *>(
  403             uprv_malloc(supportedLocalesLength * sizeof(int32_t)));
  404         if (supportedLSRs == nullptr || supportedIndexes == nullptr) {
  405             errorCode = U_MEMORY_ALLOCATION_ERROR;
  406             return;
  407         }
  408         int32_t suppLength = 0;
  409         // Determine insertion order.
  410         // Add locales immediately that are equivalent to the default.
  411         MaybeStackArray<int8_t, 100> order(supportedLocalesLength);
  412         if (order.getAlias() == nullptr) {
  413             errorCode = U_MEMORY_ALLOCATION_ERROR;
  414             return;
  415         }
  416         int32_t numParadigms = 0;
  417         for (int32_t i = 0; i < supportedLocalesLength; ++i) {
  418             const Locale &locale = *supportedLocales[i];
  419             const LSR &lsr = lsrs[i];
  420             if (defLSR == nullptr) {
  421                 U_ASSERT(i == 0);
  422                 def = &locale;
  423                 defLSR = &lsr;
  424                 order[i] = 1;
  425                 suppLength = putIfAbsent(lsr, 0, suppLength, errorCode);
  426             } else if (lsr.isEquivalentTo(*defLSR)) {
  427                 order[i] = 1;
  428                 suppLength = putIfAbsent(lsr, i, suppLength, errorCode);
  429             } else if (localeDistance.isParadigmLSR(lsr)) {
  430                 order[i] = 2;
  431                 ++numParadigms;
  432             } else {
  433                 order[i] = 3;
  434             }
  435             if (U_FAILURE(errorCode)) { return; }
  436         }
  437         // Add supported paradigm locales.
  438         int32_t paradigmLimit = suppLength + numParadigms;
  439         for (int32_t i = 0; i < supportedLocalesLength && suppLength < paradigmLimit; ++i) {
  440             if (order[i] == 2) {
  441                 suppLength = putIfAbsent(lsrs[i], i, suppLength, errorCode);
  442             }
  443         }
  444         // Add remaining supported locales.
  445         for (int32_t i = 0; i < supportedLocalesLength; ++i) {
  446             if (order[i] == 3) {
  447                 suppLength = putIfAbsent(lsrs[i], i, suppLength, errorCode);
  448             }
  449         }
  450         supportedLSRsLength = suppLength;
  451         // If supportedLSRsLength < supportedLocalesLength then
  452         // we waste as many array slots as there are duplicate supported LSRs,
  453         // but the amount of wasted space is small as long as there are few duplicates.
  454     }
  455 
  456     defaultLocale = def;
  457 
  458     if (builder.demotion_ == ULOCMATCH_DEMOTION_REGION) {
  459         demotionPerDesiredLocale = localeDistance.getDefaultDemotionPerDesiredLocale();
  460     }
  461 }
  462 
  463 LocaleMatcher::LocaleMatcher(LocaleMatcher &&src) U_NOEXCEPT :
  464         likelySubtags(src.likelySubtags),
  465         localeDistance(src.localeDistance),
  466         thresholdDistance(src.thresholdDistance),
  467         demotionPerDesiredLocale(src.demotionPerDesiredLocale),
  468         favorSubtag(src.favorSubtag),
  469         direction(src.direction),
  470         supportedLocales(src.supportedLocales), lsrs(src.lsrs),
  471         supportedLocalesLength(src.supportedLocalesLength),
  472         supportedLsrToIndex(src.supportedLsrToIndex),
  473         supportedLSRs(src.supportedLSRs),
  474         supportedIndexes(src.supportedIndexes),
  475         supportedLSRsLength(src.supportedLSRsLength),
  476         ownedDefaultLocale(src.ownedDefaultLocale), defaultLocale(src.defaultLocale) {
  477     src.supportedLocales = nullptr;
  478     src.lsrs = nullptr;
  479     src.supportedLocalesLength = 0;
  480     src.supportedLsrToIndex = nullptr;
  481     src.supportedLSRs = nullptr;
  482     src.supportedIndexes = nullptr;
  483     src.supportedLSRsLength = 0;
  484     src.ownedDefaultLocale = nullptr;
  485     src.defaultLocale = nullptr;
  486 }
  487 
  488 LocaleMatcher::~LocaleMatcher() {
  489     for (int32_t i = 0; i < supportedLocalesLength; ++i) {
  490         delete supportedLocales[i];
  491     }
  492     uprv_free(supportedLocales);
  493     delete[] lsrs;
  494     uhash_close(supportedLsrToIndex);
  495     uprv_free(supportedLSRs);
  496     uprv_free(supportedIndexes);
  497     delete ownedDefaultLocale;
  498 }
  499 
  500 LocaleMatcher &LocaleMatcher::operator=(LocaleMatcher &&src) U_NOEXCEPT {
  501     this->~LocaleMatcher();
  502 
  503     thresholdDistance = src.thresholdDistance;
  504     demotionPerDesiredLocale = src.demotionPerDesiredLocale;
  505     favorSubtag = src.favorSubtag;
  506     direction = src.direction;
  507     supportedLocales = src.supportedLocales;
  508     lsrs = src.lsrs;
  509     supportedLocalesLength = src.supportedLocalesLength;
  510     supportedLsrToIndex = src.supportedLsrToIndex;
  511     supportedLSRs = src.supportedLSRs;
  512     supportedIndexes = src.supportedIndexes;
  513     supportedLSRsLength = src.supportedLSRsLength;
  514     ownedDefaultLocale = src.ownedDefaultLocale;
  515     defaultLocale = src.defaultLocale;
  516 
  517     src.supportedLocales = nullptr;
  518     src.lsrs = nullptr;
  519     src.supportedLocalesLength = 0;
  520     src.supportedLsrToIndex = nullptr;
  521     src.supportedLSRs = nullptr;
  522     src.supportedIndexes = nullptr;
  523     src.supportedLSRsLength = 0;
  524     src.ownedDefaultLocale = nullptr;
  525     src.defaultLocale = nullptr;
  526     return *this;
  527 }
  528 
  529 class LocaleLsrIterator {
  530 public:
  531     LocaleLsrIterator(const XLikelySubtags &likelySubtags, Locale::Iterator &locales,
  532                       ULocMatchLifetime lifetime) :
  533             likelySubtags(likelySubtags), locales(locales), lifetime(lifetime) {}
  534 
  535     ~LocaleLsrIterator() {
  536         if (lifetime == ULOCMATCH_TEMPORARY_LOCALES) {
  537             delete remembered;
  538         }
  539     }
  540 
  541     bool hasNext() const {
  542         return locales.hasNext();
  543     }
  544 
  545     LSR next(UErrorCode &errorCode) {
  546         current = &locales.next();
  547         return getMaximalLsrOrUnd(likelySubtags, *current, errorCode);
  548     }
  549 
  550     void rememberCurrent(int32_t desiredIndex, UErrorCode &errorCode) {
  551         if (U_FAILURE(errorCode)) { return; }
  552         bestDesiredIndex = desiredIndex;
  553         if (lifetime == ULOCMATCH_STORED_LOCALES) {
  554             remembered = current;
  555         } else {
  556             // ULOCMATCH_TEMPORARY_LOCALES
  557             delete remembered;
  558             remembered = new Locale(*current);
  559             if (remembered == nullptr) {
  560                 errorCode = U_MEMORY_ALLOCATION_ERROR;
  561             }
  562         }
  563     }
  564 
  565     const Locale *orphanRemembered() {
  566         const Locale *rem = remembered;
  567         remembered = nullptr;
  568         return rem;
  569     }
  570 
  571     int32_t getBestDesiredIndex() const {
  572         return bestDesiredIndex;
  573     }
  574 
  575 private:
  576     const XLikelySubtags &likelySubtags;
  577     Locale::Iterator &locales;
  578     ULocMatchLifetime lifetime;
  579     const Locale *current = nullptr, *remembered = nullptr;
  580     int32_t bestDesiredIndex = -1;
  581 };
  582 
  583 const Locale *LocaleMatcher::getBestMatch(const Locale &desiredLocale, UErrorCode &errorCode) const {
  584     if (U_FAILURE(errorCode)) { return nullptr; }
  585     int32_t suppIndex = getBestSuppIndex(
  586         getMaximalLsrOrUnd(likelySubtags, desiredLocale, errorCode),
  587         nullptr, errorCode);
  588     return U_SUCCESS(errorCode) && suppIndex >= 0 ? supportedLocales[suppIndex] : defaultLocale;
  589 }
  590 
  591 const Locale *LocaleMatcher::getBestMatch(Locale::Iterator &desiredLocales,
  592                                           UErrorCode &errorCode) const {
  593     if (U_FAILURE(errorCode)) { return nullptr; }
  594     if (!desiredLocales.hasNext()) {
  595         return defaultLocale;
  596     }
  597     LocaleLsrIterator lsrIter(likelySubtags, desiredLocales, ULOCMATCH_TEMPORARY_LOCALES);
  598     int32_t suppIndex = getBestSuppIndex(lsrIter.next(errorCode), &lsrIter, errorCode);
  599     return U_SUCCESS(errorCode) && suppIndex >= 0 ? supportedLocales[suppIndex] : defaultLocale;
  600 }
  601 
  602 const Locale *LocaleMatcher::getBestMatchForListString(
  603         StringPiece desiredLocaleList, UErrorCode &errorCode) const {
  604     LocalePriorityList list(desiredLocaleList, errorCode);
  605     LocalePriorityList::Iterator iter = list.iterator();
  606     return getBestMatch(iter, errorCode);
  607 }
  608 
  609 LocaleMatcher::Result LocaleMatcher::getBestMatchResult(
  610         const Locale &desiredLocale, UErrorCode &errorCode) const {
  611     if (U_FAILURE(errorCode)) {
  612         return Result(nullptr, defaultLocale, -1, -1, FALSE);
  613     }
  614     int32_t suppIndex = getBestSuppIndex(
  615         getMaximalLsrOrUnd(likelySubtags, desiredLocale, errorCode),
  616         nullptr, errorCode);
  617     if (U_FAILURE(errorCode) || suppIndex < 0) {
  618         return Result(nullptr, defaultLocale, -1, -1, FALSE);
  619     } else {
  620         return Result(&desiredLocale, supportedLocales[suppIndex], 0, suppIndex, FALSE);
  621     }
  622 }
  623 
  624 LocaleMatcher::Result LocaleMatcher::getBestMatchResult(
  625         Locale::Iterator &desiredLocales, UErrorCode &errorCode) const {
  626     if (U_FAILURE(errorCode) || !desiredLocales.hasNext()) {
  627         return Result(nullptr, defaultLocale, -1, -1, FALSE);
  628     }
  629     LocaleLsrIterator lsrIter(likelySubtags, desiredLocales, ULOCMATCH_TEMPORARY_LOCALES);
  630     int32_t suppIndex = getBestSuppIndex(lsrIter.next(errorCode), &lsrIter, errorCode);
  631     if (U_FAILURE(errorCode) || suppIndex < 0) {
  632         return Result(nullptr, defaultLocale, -1, -1, FALSE);
  633     } else {
  634         return Result(lsrIter.orphanRemembered(), supportedLocales[suppIndex],
  635                       lsrIter.getBestDesiredIndex(), suppIndex, TRUE);
  636     }
  637 }
  638 
  639 int32_t LocaleMatcher::getBestSuppIndex(LSR desiredLSR, LocaleLsrIterator *remainingIter,
  640                                         UErrorCode &errorCode) const {
  641     if (U_FAILURE(errorCode)) { return -1; }
  642     int32_t desiredIndex = 0;
  643     int32_t bestSupportedLsrIndex = -1;
  644     for (int32_t bestShiftedDistance = LocaleDistance::shiftDistance(thresholdDistance);;) {
  645         // Quick check for exact maximized LSR.
  646         // Returns suppIndex+1 where 0 means not found.
  647         if (supportedLsrToIndex != nullptr) {
  648             desiredLSR.setHashCode();
  649             int32_t index = uhash_geti(supportedLsrToIndex, &desiredLSR);
  650             if (index != 0) {
  651                 int32_t suppIndex = index - 1;
  652                 if (remainingIter != nullptr) {
  653                     remainingIter->rememberCurrent(desiredIndex, errorCode);
  654                 }
  655                 return suppIndex;
  656             }
  657         }
  658         int32_t bestIndexAndDistance = localeDistance.getBestIndexAndDistance(
  659                 desiredLSR, supportedLSRs, supportedLSRsLength,
  660                 bestShiftedDistance, favorSubtag, direction);
  661         if (bestIndexAndDistance >= 0) {
  662             bestShiftedDistance = LocaleDistance::getShiftedDistance(bestIndexAndDistance);
  663             if (remainingIter != nullptr) {
  664                 remainingIter->rememberCurrent(desiredIndex, errorCode);
  665                 if (U_FAILURE(errorCode)) { return -1; }
  666             }
  667             bestSupportedLsrIndex = LocaleDistance::getIndex(bestIndexAndDistance);
  668         }
  669         if ((bestShiftedDistance -= LocaleDistance::shiftDistance(demotionPerDesiredLocale)) <= 0) {
  670             break;
  671         }
  672         if (remainingIter == nullptr || !remainingIter->hasNext()) {
  673             break;
  674         }
  675         desiredLSR = remainingIter->next(errorCode);
  676         if (U_FAILURE(errorCode)) { return -1; }
  677         ++desiredIndex;
  678     }
  679     if (bestSupportedLsrIndex < 0) {
  680         // no good match
  681         return -1;
  682     }
  683     return supportedIndexes[bestSupportedLsrIndex];
  684 }
  685 
  686 double LocaleMatcher::internalMatch(const Locale &desired, const Locale &supported, UErrorCode &errorCode) const {
  687     // Returns the inverse of the distance: That is, 1-distance(desired, supported).
  688     LSR suppLSR = getMaximalLsrOrUnd(likelySubtags, supported, errorCode);
  689     if (U_FAILURE(errorCode)) { return 0; }
  690     const LSR *pSuppLSR = &suppLSR;
  691     int32_t indexAndDistance = localeDistance.getBestIndexAndDistance(
  692             getMaximalLsrOrUnd(likelySubtags, desired, errorCode),
  693             &pSuppLSR, 1,
  694             LocaleDistance::shiftDistance(thresholdDistance), favorSubtag, direction);
  695     double distance = LocaleDistance::getDistanceDouble(indexAndDistance);
  696     return (100.0 - distance) / 100.0;
  697 }
  698 
  699 U_NAMESPACE_END
  700 
  701 // uloc_acceptLanguage() --------------------------------------------------- ***
  702 
  703 U_NAMESPACE_USE
  704 
  705 namespace {
  706 
  707 class LocaleFromTag {
  708 public:
  709     LocaleFromTag() : locale(Locale::getRoot()) {}
  710     const Locale &operator()(const char *tag) { return locale = Locale(tag); }
  711 
  712 private:
  713     // Store the locale in the converter, rather than return a reference to a temporary,
  714     // or a value which could go out of scope with the caller's reference to it.
  715     Locale locale;
  716 };
  717 
  718 int32_t acceptLanguage(UEnumeration &supportedLocales, Locale::Iterator &desiredLocales,
  719                        char *dest, int32_t capacity, UAcceptResult *acceptResult,
  720                        UErrorCode &errorCode) {
  721     if (U_FAILURE(errorCode)) { return 0; }
  722     LocaleMatcher::Builder builder;
  723     const char *locString;
  724     while ((locString = uenum_next(&supportedLocales, nullptr, &errorCode)) != nullptr) {
  725         Locale loc(locString);
  726         if (loc.isBogus()) {
  727             errorCode = U_ILLEGAL_ARGUMENT_ERROR;
  728             return 0;
  729         }
  730         builder.addSupportedLocale(loc);
  731     }
  732     LocaleMatcher matcher = builder.build(errorCode);
  733     LocaleMatcher::Result result = matcher.getBestMatchResult(desiredLocales, errorCode);
  734     if (U_FAILURE(errorCode)) { return 0; }
  735     if (result.getDesiredIndex() >= 0) {
  736         if (acceptResult != nullptr) {
  737             *acceptResult = *result.getDesiredLocale() == *result.getSupportedLocale() ?
  738                 ULOC_ACCEPT_VALID : ULOC_ACCEPT_FALLBACK;
  739         }
  740         const char *bestStr = result.getSupportedLocale()->getName();
  741         int32_t bestLength = (int32_t)uprv_strlen(bestStr);
  742         if (bestLength <= capacity) {
  743             uprv_memcpy(dest, bestStr, bestLength);
  744         }
  745         return u_terminateChars(dest, capacity, bestLength, &errorCode);
  746     } else {
  747         if (acceptResult != nullptr) {
  748             *acceptResult = ULOC_ACCEPT_FAILED;
  749         }
  750         return u_terminateChars(dest, capacity, 0, &errorCode);
  751     }
  752 }
  753 
  754 }  // namespace
  755 
  756 U_CAPI int32_t U_EXPORT2
  757 uloc_acceptLanguage(char *result, int32_t resultAvailable,
  758                     UAcceptResult *outResult,
  759                     const char **acceptList, int32_t acceptListCount,
  760                     UEnumeration *availableLocales,
  761                     UErrorCode *status) {
  762     if (U_FAILURE(*status)) { return 0; }
  763     if ((result == nullptr ? resultAvailable != 0 : resultAvailable < 0) ||
  764             (acceptList == nullptr ? acceptListCount != 0 : acceptListCount < 0) ||
  765             availableLocales == nullptr) {
  766         *status = U_ILLEGAL_ARGUMENT_ERROR;
  767         return 0;
  768     }
  769     LocaleFromTag converter;
  770     Locale::ConvertingIterator<const char **, LocaleFromTag> desiredLocales(
  771         acceptList, acceptList + acceptListCount, converter);
  772     return acceptLanguage(*availableLocales, desiredLocales,
  773                           result, resultAvailable, outResult, *status);
  774 }
  775 
  776 U_CAPI int32_t U_EXPORT2
  777 uloc_acceptLanguageFromHTTP(char *result, int32_t resultAvailable,
  778                             UAcceptResult *outResult,
  779                             const char *httpAcceptLanguage,
  780                             UEnumeration *availableLocales,
  781                             UErrorCode *status) {
  782     if (U_FAILURE(*status)) { return 0; }
  783     if ((result == nullptr ? resultAvailable != 0 : resultAvailable < 0) ||
  784             httpAcceptLanguage == nullptr || availableLocales == nullptr) {
  785         *status = U_ILLEGAL_ARGUMENT_ERROR;
  786         return 0;
  787     }
  788     LocalePriorityList list(httpAcceptLanguage, *status);
  789     LocalePriorityList::Iterator desiredLocales = list.iterator();
  790     return acceptLanguage(*availableLocales, desiredLocales,
  791                           result, resultAvailable, outResult, *status);
  792 }
  793 
  794 #endif  // __LOCMATCHER_H__