localematcher.cpp 31 KB

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