/** * Indicator for the lifetime of desired-locale objects passed into the LocaleMatcher. * * @draft ICU 65
*/ enum ULocMatchLifetime { /** * Locale objects are temporary. * The matcher will make a copy of a locale that will be used beyond one function call. * * @draft ICU 65
*/
ULOCMATCH_TEMPORARY_LOCALES, /** * Locale objects are stored at least as long as the matcher is used. * The matcher will keep only a pointer to a locale that will be used beyond one function call, * avoiding a copy. * * @draft ICU 65
*/
ULOCMATCH_STORED_LOCALES // TODO: permanent? cached? clone?
}; #ifndef U_IN_DOXYGEN typedefenum ULocMatchLifetime ULocMatchLifetime; #endif
// Copy the region from bestDesired, if there is one. constchar *region = bestDesired->getCountry(); if (*region != 0) {
b.setRegion(region);
}
// Copy the variants from bestDesired, if there are any. // Note that this will override any supportedLocale variants. // For example, "sco-ulster-fonipa" + "...-fonupa" => "sco-fonupa" (replacing ulster). constchar *variants = bestDesired->getVariant(); if (*variants != 0) {
b.setVariant(variants);
}
// Copy the extensions from bestDesired, if there are any. // C++ note: The following note, copied from Java, may not be true, // as long as C++ copies by legacy ICU keyword, not by extension singleton. // Note that this will override any supportedLocale extensions. // For example, "th-u-nu-latn-ca-buddhist" + "...-u-nu-native" => "th-u-nu-native" // (replacing calendar).
b.copyExtensionsFrom(*bestDesired, errorCode); return b.build(errorCode);
}
int32_t LocaleMatcher::putIfAbsent(const LSR &lsr, int32_t i, int32_t suppLength,
UErrorCode &errorCode) { if (U_FAILURE(errorCode)) { return suppLength; } if (!uhash_containsKey(supportedLsrToIndex, &lsr)) {
uhash_putiAllowZero(supportedLsrToIndex, const_cast<LSR *>(&lsr), i, &errorCode); if (U_SUCCESS(errorCode)) {
supportedLSRs[suppLength] = &lsr;
supportedIndexes[suppLength++] = i;
}
} return suppLength;
}
LocaleMatcher::LocaleMatcher(const Builder &builder, UErrorCode &errorCode) :
likelySubtags(*LikelySubtags::getSingleton(errorCode)),
localeDistance(*LocaleDistance::getSingleton(errorCode)),
thresholdDistance(builder.thresholdDistance_),
demotionPerDesiredLocale(0),
favorSubtag(builder.favor_),
direction(builder.direction_),
supportedLocales(nullptr), lsrs(nullptr), supportedLocalesLength(0),
supportedLsrToIndex(nullptr),
supportedLSRs(nullptr), supportedIndexes(nullptr), supportedLSRsLength(0),
ownedDefaultLocale(nullptr), defaultLocale(nullptr) { if (U_FAILURE(errorCode)) { return; } const Locale *def = builder.defaultLocale_;
LSR builderDefaultLSR; const LSR *defLSR = nullptr; if (def != nullptr) {
ownedDefaultLocale = def->clone(); if (ownedDefaultLocale == nullptr) {
errorCode = U_MEMORY_ALLOCATION_ERROR; return;
}
def = ownedDefaultLocale;
builderDefaultLSR = getMaximalLsrOrUnd(likelySubtags, *def, errorCode); if (U_FAILURE(errorCode)) { return; }
defLSR = &builderDefaultLSR;
}
supportedLocalesLength = builder.supportedLocales_ != nullptr ?
builder.supportedLocales_->size() : 0; if (supportedLocalesLength > 0) { // Store the supported locales in input order, // so that when different types are used (e.g., language tag strings) // we can return those by parallel index.
supportedLocales = static_cast<const Locale **>(
uprv_malloc(supportedLocalesLength * sizeof(const Locale *))); // Supported LRSs in input order. // In C++, we store these permanently to simplify ownership management // in the hash tables. Duplicate LSRs (if any) are unused overhead.
lsrs = new LSR[supportedLocalesLength]; if (supportedLocales == nullptr || lsrs == nullptr) {
errorCode = U_MEMORY_ALLOCATION_ERROR; return;
} // If the constructor fails partway, we need null pointers for destructibility.
uprv_memset(supportedLocales, 0, supportedLocalesLength * sizeof(const Locale *)); for (int32_t i = 0; i < supportedLocalesLength; ++i) { const Locale &locale = *static_cast<Locale *>(builder.supportedLocales_->elementAt(i));
supportedLocales[i] = locale.clone(); if (supportedLocales[i] == nullptr) {
errorCode = U_MEMORY_ALLOCATION_ERROR; return;
} const Locale &supportedLocale = *supportedLocales[i];
LSR &lsr = lsrs[i] = getMaximalLsrOrUnd(likelySubtags, supportedLocale, errorCode);
lsr.setHashCode(); if (U_FAILURE(errorCode)) { return; }
}
// We need an unordered map from LSR to first supported locale with that LSR, // and an ordered list of (LSR, supported index) for // the supported locales in the following order: // 1. Default locale, if it is supported. // 2. Priority locales (aka "paradigm locales") in builder order. // 3. Remaining locales in builder order.
supportedLsrToIndex = uhash_openSize(hashLSR, compareLSRs, uhash_compareLong,
supportedLocalesLength, &errorCode); if (U_FAILURE(errorCode)) { return; }
supportedLSRs = static_cast<const LSR **>(
uprv_malloc(supportedLocalesLength * sizeof(const LSR *)));
supportedIndexes = static_cast<int32_t *>(
uprv_malloc(supportedLocalesLength * sizeof(int32_t))); if (supportedLSRs == nullptr || supportedIndexes == nullptr) {
errorCode = U_MEMORY_ALLOCATION_ERROR; return;
}
int32_t suppLength = 0; // Determine insertion order. // Add locales immediately that are equivalent to the default.
MaybeStackArray<int8_t, 100> order(supportedLocalesLength, errorCode); if (U_FAILURE(errorCode)) { return; }
int32_t numParadigms = 0; for (int32_t i = 0; i < supportedLocalesLength; ++i) { const Locale &locale = *supportedLocales[i]; const LSR &lsr = lsrs[i]; if (defLSR == nullptr && builder.withDefault_) { // Implicit default locale = first supported locale, if not turned off.
U_ASSERT(i == 0);
def = &locale;
defLSR = &lsr;
order[i] = 1;
suppLength = putIfAbsent(lsr, 0, suppLength, errorCode);
} elseif (defLSR != nullptr && lsr.isEquivalentTo(*defLSR)) {
order[i] = 1;
suppLength = putIfAbsent(lsr, i, suppLength, errorCode);
} elseif (localeDistance.isParadigmLSR(lsr)) {
order[i] = 2;
++numParadigms;
} else {
order[i] = 3;
} if (U_FAILURE(errorCode)) { return; }
} // Add supported paradigm locales.
int32_t paradigmLimit = suppLength + numParadigms; for (int32_t i = 0; i < supportedLocalesLength && suppLength < paradigmLimit; ++i) { if (order[i] == 2) {
suppLength = putIfAbsent(lsrs[i], i, suppLength, errorCode);
}
} // Add remaining supported locales. for (int32_t i = 0; i < supportedLocalesLength; ++i) { if (order[i] == 3) {
suppLength = putIfAbsent(lsrs[i], i, suppLength, errorCode);
}
}
supportedLSRsLength = suppLength; // If supportedLSRsLength < supportedLocalesLength then // we waste as many array slots as there are duplicate supported LSRs, // but the amount of wasted space is small as long as there are few duplicates.
}
defaultLocale = def;
if (builder.demotion_ == ULOCMATCH_DEMOTION_REGION) {
demotionPerDesiredLocale = localeDistance.getDefaultDemotionPerDesiredLocale();
}
private: // Store the locale in the converter, rather than return a reference to a temporary, // or a value which could go out of scope with the caller's reference to it.
Locale locale;
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.