8358426: Improve lazy computation in Locale
Reviewed-by: naoto, liach
This commit is contained in:
parent
fcb68ea22d
commit
cd9b1bc820
@ -48,8 +48,8 @@ import java.io.Serializable;
|
|||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.text.ParsePosition;
|
import java.text.ParsePosition;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import java.util.spi.LocaleNameProvider;
|
import java.util.spi.LocaleNameProvider;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@ -733,58 +733,24 @@ public final class Locale implements Cloneable, Serializable {
|
|||||||
* @see #getISOCountries(Locale.IsoCountryCode)
|
* @see #getISOCountries(Locale.IsoCountryCode)
|
||||||
* @since 9
|
* @since 9
|
||||||
*/
|
*/
|
||||||
public static enum IsoCountryCode {
|
public enum IsoCountryCode {
|
||||||
/**
|
/**
|
||||||
* PART1_ALPHA2 is used to represent the ISO3166-1 alpha-2 two letter
|
* PART1_ALPHA2 is used to represent the ISO3166-1 alpha-2 two letter
|
||||||
* country codes.
|
* country codes.
|
||||||
*/
|
*/
|
||||||
PART1_ALPHA2 {
|
PART1_ALPHA2,
|
||||||
@Override
|
|
||||||
Set<String> createCountryCodeSet() {
|
|
||||||
return Set.of(Locale.getISOCountries());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* PART1_ALPHA3 is used to represent the ISO3166-1 alpha-3 three letter
|
* PART1_ALPHA3 is used to represent the ISO3166-1 alpha-3 three letter
|
||||||
* country codes.
|
* country codes.
|
||||||
*/
|
*/
|
||||||
PART1_ALPHA3 {
|
PART1_ALPHA3,
|
||||||
@Override
|
|
||||||
Set<String> createCountryCodeSet() {
|
|
||||||
return LocaleISOData.computeISO3166_1Alpha3Countries();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PART3 is used to represent the ISO3166-3 four letter country codes.
|
* PART3 is used to represent the ISO3166-3 four letter country codes.
|
||||||
*/
|
*/
|
||||||
PART3 {
|
PART3
|
||||||
@Override
|
|
||||||
Set<String> createCountryCodeSet() {
|
|
||||||
return Set.of(LocaleISOData.ISO3166_3);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Concrete implementation of this method attempts to compute value
|
|
||||||
* for iso3166CodesMap for each IsoCountryCode type key.
|
|
||||||
*/
|
|
||||||
abstract Set<String> createCountryCodeSet();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Map to hold country codes for each ISO3166 part.
|
|
||||||
*/
|
|
||||||
private static final Map<IsoCountryCode, Set<String>> iso3166CodesMap = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is called from Locale class to retrieve country code set
|
|
||||||
* for getISOCountries(type)
|
|
||||||
*/
|
|
||||||
static Set<String> retrieveISOCountryCodes(IsoCountryCode type) {
|
|
||||||
return iso3166CodesMap.computeIfAbsent(type, IsoCountryCode::createCountryCodeSet);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1004,30 +970,28 @@ public final class Locale implements Cloneable, Serializable {
|
|||||||
return getInstance(baseloc, extensions);
|
return getInstance(baseloc, extensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Locale getInstance(BaseLocale baseloc, LocaleExtensions extensions) {
|
static Locale getInstance(BaseLocale baseloc, LocaleExtensions extensions) {
|
||||||
if (extensions == null) {
|
if (extensions == null) {
|
||||||
Locale locale = CONSTANT_LOCALES.get(baseloc);
|
Locale locale = CONSTANT_LOCALES.get(baseloc);
|
||||||
if (locale != null) {
|
if (locale != null) {
|
||||||
return locale;
|
return locale;
|
||||||
}
|
}
|
||||||
return LocaleCache.cache(baseloc);
|
return LOCALE_CACHE.get().computeIfAbsent(baseloc, LOCALE_CREATOR);
|
||||||
} else {
|
} else {
|
||||||
LocaleKey key = new LocaleKey(baseloc, extensions);
|
LocaleKey key = new LocaleKey(baseloc, extensions);
|
||||||
return LocaleCache.cache(key);
|
return LOCALE_CACHE.get().computeIfAbsent(key, LOCALE_CREATOR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class LocaleCache implements Function<Object, Locale> {
|
private static final Supplier<ReferencedKeyMap<Object, Locale>> LOCALE_CACHE =
|
||||||
private static final ReferencedKeyMap<Object, Locale> LOCALE_CACHE
|
StableValue.supplier(new Supplier<>() {
|
||||||
= ReferencedKeyMap.create(true, ReferencedKeyMap.concurrentHashMapSupplier());
|
@Override
|
||||||
|
public ReferencedKeyMap<Object, Locale> get() {
|
||||||
private static final Function<Object, Locale> LOCALE_CREATOR = new LocaleCache();
|
return ReferencedKeyMap.create(true, ReferencedKeyMap.concurrentHashMapSupplier());
|
||||||
|
}
|
||||||
public static Locale cache(Object key) {
|
});
|
||||||
return LOCALE_CACHE.computeIfAbsent(key, LOCALE_CREATOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
private static final Function<Object, Locale> LOCALE_CREATOR = new Function<>() {
|
||||||
@Override
|
@Override
|
||||||
public Locale apply(Object key) {
|
public Locale apply(Object key) {
|
||||||
if (key instanceof BaseLocale base) {
|
if (key instanceof BaseLocale base) {
|
||||||
@ -1036,7 +1000,7 @@ public final class Locale implements Cloneable, Serializable {
|
|||||||
LocaleKey lk = (LocaleKey)key;
|
LocaleKey lk = (LocaleKey)key;
|
||||||
return new Locale(lk.base, lk.exts);
|
return new Locale(lk.base, lk.exts);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
private static final class LocaleKey {
|
private static final class LocaleKey {
|
||||||
|
|
||||||
@ -1301,12 +1265,8 @@ public final class Locale implements Cloneable, Serializable {
|
|||||||
* @return An array of ISO 3166 two-letter country codes.
|
* @return An array of ISO 3166 two-letter country codes.
|
||||||
*/
|
*/
|
||||||
public static String[] getISOCountries() {
|
public static String[] getISOCountries() {
|
||||||
if (isoCountries == null) {
|
String[] countries = LocaleISOData.ISO_3166_1_ALPHA2.get();
|
||||||
isoCountries = getISO2Table(LocaleISOData.isoCountryTable);
|
return Arrays.copyOf(countries, countries.length);
|
||||||
}
|
|
||||||
String[] result = new String[isoCountries.length];
|
|
||||||
System.arraycopy(isoCountries, 0, result, 0, isoCountries.length);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1319,7 +1279,11 @@ public final class Locale implements Cloneable, Serializable {
|
|||||||
*/
|
*/
|
||||||
public static Set<String> getISOCountries(IsoCountryCode type) {
|
public static Set<String> getISOCountries(IsoCountryCode type) {
|
||||||
Objects.requireNonNull(type);
|
Objects.requireNonNull(type);
|
||||||
return IsoCountryCode.retrieveISOCountryCodes(type);
|
return switch (type) {
|
||||||
|
case PART1_ALPHA2 -> Set.of(LocaleISOData.ISO_3166_1_ALPHA2.get());
|
||||||
|
case PART1_ALPHA3 -> LocaleISOData.ISO_3166_1_ALPHA3.get();
|
||||||
|
case PART3 -> LocaleISOData.ISO_3166_3.get();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1339,22 +1303,8 @@ public final class Locale implements Cloneable, Serializable {
|
|||||||
* @return An array of ISO 639 two-letter language codes.
|
* @return An array of ISO 639 two-letter language codes.
|
||||||
*/
|
*/
|
||||||
public static String[] getISOLanguages() {
|
public static String[] getISOLanguages() {
|
||||||
String[] languages = Locale.isoLanguages;
|
String[] languages = LocaleISOData.ISO_639.get();
|
||||||
if (languages == null) {
|
return Arrays.copyOf(languages, languages.length);
|
||||||
Locale.isoLanguages = languages = getISO2Table(LocaleISOData.isoLanguageTable);
|
|
||||||
}
|
|
||||||
String[] result = new String[languages.length];
|
|
||||||
System.arraycopy(languages, 0, result, 0, languages.length);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String[] getISO2Table(String table) {
|
|
||||||
int len = table.length() / 5;
|
|
||||||
String[] isoTable = new String[len];
|
|
||||||
for (int i = 0, j = 0; i < len; i++, j += 5) {
|
|
||||||
isoTable[i] = table.substring(j, j + 2);
|
|
||||||
}
|
|
||||||
return isoTable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1683,61 +1633,54 @@ public final class Locale implements Cloneable, Serializable {
|
|||||||
* @since 1.7
|
* @since 1.7
|
||||||
*/
|
*/
|
||||||
public String toLanguageTag() {
|
public String toLanguageTag() {
|
||||||
String lTag = this.languageTag;
|
return languageTag.get();
|
||||||
if (lTag != null) {
|
}
|
||||||
return lTag;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
private String computeLanguageTag() {
|
||||||
LanguageTag tag = LanguageTag.parseLocale(baseLocale, localeExtensions);
|
LanguageTag tag = LanguageTag.parseLocale(baseLocale, localeExtensions);
|
||||||
StringBuilder buf = new StringBuilder();
|
StringBuilder bldr = new StringBuilder();
|
||||||
|
|
||||||
String subtag = tag.language();
|
String subtag = tag.language();
|
||||||
if (!subtag.isEmpty()) {
|
if (!subtag.isEmpty()) {
|
||||||
buf.append(LanguageTag.canonicalizeLanguage(subtag));
|
bldr.append(LanguageTag.canonicalizeLanguage(subtag));
|
||||||
}
|
}
|
||||||
|
|
||||||
subtag = tag.script();
|
subtag = tag.script();
|
||||||
if (!subtag.isEmpty()) {
|
if (!subtag.isEmpty()) {
|
||||||
buf.append(LanguageTag.SEP);
|
bldr.append(LanguageTag.SEP);
|
||||||
buf.append(LanguageTag.canonicalizeScript(subtag));
|
bldr.append(LanguageTag.canonicalizeScript(subtag));
|
||||||
}
|
}
|
||||||
|
|
||||||
subtag = tag.region();
|
subtag = tag.region();
|
||||||
if (!subtag.isEmpty()) {
|
if (!subtag.isEmpty()) {
|
||||||
buf.append(LanguageTag.SEP);
|
bldr.append(LanguageTag.SEP);
|
||||||
buf.append(LanguageTag.canonicalizeRegion(subtag));
|
bldr.append(LanguageTag.canonicalizeRegion(subtag));
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String>subtags = tag.variants();
|
List<String>subtags = tag.variants();
|
||||||
for (String s : subtags) {
|
for (String s : subtags) {
|
||||||
buf.append(LanguageTag.SEP);
|
bldr.append(LanguageTag.SEP);
|
||||||
// preserve casing
|
// preserve casing
|
||||||
buf.append(s);
|
bldr.append(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
subtags = tag.extensions();
|
subtags = tag.extensions();
|
||||||
for (String s : subtags) {
|
for (String s : subtags) {
|
||||||
buf.append(LanguageTag.SEP);
|
bldr.append(LanguageTag.SEP);
|
||||||
buf.append(LanguageTag.canonicalizeExtension(s));
|
bldr.append(LanguageTag.canonicalizeExtension(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
subtag = tag.privateuse();
|
subtag = tag.privateuse();
|
||||||
if (!subtag.isEmpty()) {
|
if (!subtag.isEmpty()) {
|
||||||
if (buf.length() > 0) {
|
if (bldr.length() > 0) {
|
||||||
buf.append(LanguageTag.SEP);
|
bldr.append(LanguageTag.SEP);
|
||||||
}
|
}
|
||||||
buf.append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP);
|
bldr.append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP);
|
||||||
// preserve casing
|
// preserve casing
|
||||||
buf.append(subtag);
|
bldr.append(subtag);
|
||||||
}
|
}
|
||||||
|
|
||||||
String langTag = buf.toString();
|
return bldr.toString();
|
||||||
synchronized (this) {
|
|
||||||
if (this.languageTag == null) {
|
|
||||||
this.languageTag = langTag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return langTag;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1961,7 +1904,7 @@ public final class Locale implements Cloneable, Serializable {
|
|||||||
return lang;
|
return lang;
|
||||||
}
|
}
|
||||||
|
|
||||||
String language3 = getISO3Code(lang, LocaleISOData.isoLanguageTable);
|
String language3 = LocaleISOData.getISO3LangCode(lang);
|
||||||
if (language3 == null) {
|
if (language3 == null) {
|
||||||
throw new MissingResourceException("Couldn't find 3-letter language code for "
|
throw new MissingResourceException("Couldn't find 3-letter language code for "
|
||||||
+ lang, "FormatData_" + toString(), "ShortLanguage");
|
+ lang, "FormatData_" + toString(), "ShortLanguage");
|
||||||
@ -1983,7 +1926,7 @@ public final class Locale implements Cloneable, Serializable {
|
|||||||
* three-letter country abbreviation is not available for this locale.
|
* three-letter country abbreviation is not available for this locale.
|
||||||
*/
|
*/
|
||||||
public String getISO3Country() throws MissingResourceException {
|
public String getISO3Country() throws MissingResourceException {
|
||||||
String country3 = getISO3Code(baseLocale.getRegion(), LocaleISOData.isoCountryTable);
|
String country3 = LocaleISOData.getISO3CtryCode(baseLocale.getRegion());
|
||||||
if (country3 == null) {
|
if (country3 == null) {
|
||||||
throw new MissingResourceException("Couldn't find 3-letter country code for "
|
throw new MissingResourceException("Couldn't find 3-letter country code for "
|
||||||
+ baseLocale.getRegion(), "FormatData_" + toString(), "ShortCountry");
|
+ baseLocale.getRegion(), "FormatData_" + toString(), "ShortCountry");
|
||||||
@ -1991,27 +1934,6 @@ public final class Locale implements Cloneable, Serializable {
|
|||||||
return country3;
|
return country3;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getISO3Code(String iso2Code, String table) {
|
|
||||||
int codeLength = iso2Code.length();
|
|
||||||
if (codeLength == 0) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
int tableLength = table.length();
|
|
||||||
int index = tableLength;
|
|
||||||
if (codeLength == 2) {
|
|
||||||
char c1 = iso2Code.charAt(0);
|
|
||||||
char c2 = iso2Code.charAt(1);
|
|
||||||
for (index = 0; index < tableLength; index += 5) {
|
|
||||||
if (table.charAt(index) == c1
|
|
||||||
&& table.charAt(index + 1) == c2) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return index < tableLength ? table.substring(index + 2, index + 5) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a name for the locale's language that is appropriate for display to the
|
* Returns a name for the locale's language that is appropriate for display to the
|
||||||
* user.
|
* user.
|
||||||
@ -2393,7 +2315,13 @@ public final class Locale implements Cloneable, Serializable {
|
|||||||
private static volatile Locale defaultDisplayLocale;
|
private static volatile Locale defaultDisplayLocale;
|
||||||
private static volatile Locale defaultFormatLocale;
|
private static volatile Locale defaultFormatLocale;
|
||||||
|
|
||||||
private transient volatile String languageTag;
|
private final transient Supplier<String> languageTag =
|
||||||
|
StableValue.supplier(new Supplier<>() {
|
||||||
|
@Override
|
||||||
|
public String get() {
|
||||||
|
return computeLanguageTag();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an array of the display names of the variant.
|
* Return an array of the display names of the variant.
|
||||||
@ -2587,10 +2515,6 @@ public final class Locale implements Cloneable, Serializable {
|
|||||||
baseLocale.getRegion(), baseLocale.getVariant(), localeExtensions);
|
baseLocale.getRegion(), baseLocale.getVariant(), localeExtensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static volatile String[] isoLanguages;
|
|
||||||
|
|
||||||
private static volatile String[] isoCountries;
|
|
||||||
|
|
||||||
private static String convertOldISOCodes(String language) {
|
private static String convertOldISOCodes(String language) {
|
||||||
// we accept both the old and the new ISO codes for the languages whose ISO
|
// we accept both the old and the new ISO codes for the languages whose ISO
|
||||||
// codes have changed, but we always store the NEW code, unless the property
|
// codes have changed, but we always store the NEW code, unless the property
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -25,11 +25,47 @@
|
|||||||
|
|
||||||
package java.util;
|
package java.util;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
// Methods and suppliers for producing ISO 639/3166 resources used by Locale.
|
||||||
class LocaleISOData {
|
class LocaleISOData {
|
||||||
|
|
||||||
|
static final Supplier<String[]> ISO_639 =
|
||||||
|
StableValue.supplier(new Supplier<>() {
|
||||||
|
@Override
|
||||||
|
public String[] get() {
|
||||||
|
return getISO2Table(isoLanguageTable);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
static final Supplier<String[]> ISO_3166_1_ALPHA2 =
|
||||||
|
StableValue.supplier(new Supplier<>() {
|
||||||
|
@Override
|
||||||
|
public String[] get() {
|
||||||
|
return getISO2Table(isoCountryTable);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
static final Supplier<Set<String>> ISO_3166_1_ALPHA3 =
|
||||||
|
StableValue.supplier(new Supplier<>() {
|
||||||
|
@Override
|
||||||
|
public Set<String> get() {
|
||||||
|
return computeISO3166_1Alpha3Countries();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
static final Supplier<Set<String>> ISO_3166_3 =
|
||||||
|
StableValue.supplier(new Supplier<>() {
|
||||||
|
@Override
|
||||||
|
public Set<String> get() {
|
||||||
|
return Set.of(ISO3166_3);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The 2- and 3-letter ISO 639 language codes.
|
* The 2- and 3-letter ISO 639 language codes.
|
||||||
*/
|
*/
|
||||||
static final String isoLanguageTable =
|
private static final String isoLanguageTable =
|
||||||
"aa" + "aar" // Afar
|
"aa" + "aar" // Afar
|
||||||
+ "ab" + "abk" // Abkhazian
|
+ "ab" + "abk" // Abkhazian
|
||||||
+ "ae" + "ave" // Avestan
|
+ "ae" + "ave" // Avestan
|
||||||
@ -223,7 +259,7 @@ class LocaleISOData {
|
|||||||
/**
|
/**
|
||||||
* The 2- and 3-letter ISO 3166 country codes.
|
* The 2- and 3-letter ISO 3166 country codes.
|
||||||
*/
|
*/
|
||||||
static final String isoCountryTable =
|
private static final String isoCountryTable =
|
||||||
"AD" + "AND" // Andorra, Principality of
|
"AD" + "AND" // Andorra, Principality of
|
||||||
+ "AE" + "ARE" // United Arab Emirates
|
+ "AE" + "ARE" // United Arab Emirates
|
||||||
+ "AF" + "AFG" // Afghanistan
|
+ "AF" + "AFG" // Afghanistan
|
||||||
@ -480,18 +516,60 @@ class LocaleISOData {
|
|||||||
/**
|
/**
|
||||||
* Array to hold country codes for ISO3166-3.
|
* Array to hold country codes for ISO3166-3.
|
||||||
*/
|
*/
|
||||||
static final String[] ISO3166_3 = {
|
private static final String[] ISO3166_3 = {
|
||||||
"AIDJ", "ANHH", "BQAQ", "BUMM", "BYAA", "CSHH", "CSXX", "CTKI", "DDDE",
|
"AIDJ", "ANHH", "BQAQ", "BUMM", "BYAA", "CSHH", "CSXX", "CTKI", "DDDE",
|
||||||
"DYBJ", "FQHH", "FXFR", "GEHH", "HVBF", "JTUM", "MIUM", "NHVU", "NQAQ",
|
"DYBJ", "FQHH", "FXFR", "GEHH", "HVBF", "JTUM", "MIUM", "NHVU", "NQAQ",
|
||||||
"NTHH", "PCHH", "PUUM", "PZPA", "RHZW", "SKIN", "SUHH", "TPTL", "VDVN",
|
"NTHH", "PCHH", "PUUM", "PZPA", "RHZW", "SKIN", "SUHH", "TPTL", "VDVN",
|
||||||
"WKUM", "YDYE", "YUCS", "ZRCD"
|
"WKUM", "YDYE", "YUCS", "ZRCD"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static String getISO3LangCode(String language) {
|
||||||
|
return getISO3Code(language, isoLanguageTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getISO3CtryCode(String country) {
|
||||||
|
return getISO3Code(country, isoCountryTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getISO3Code(String iso2Code, String table) {
|
||||||
|
int codeLength = iso2Code.length();
|
||||||
|
if (codeLength == 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
int tableLength = table.length();
|
||||||
|
int index = tableLength;
|
||||||
|
if (codeLength == 2) {
|
||||||
|
char c1 = iso2Code.charAt(0);
|
||||||
|
char c2 = iso2Code.charAt(1);
|
||||||
|
for (index = 0; index < tableLength; index += 5) {
|
||||||
|
if (table.charAt(index) == c1
|
||||||
|
&& table.charAt(index + 1) == c2) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return index < tableLength ? table.substring(index + 2, index + 5) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method computes an array of alpha-2 codes from either ISO639 or
|
||||||
|
* ISO3166.
|
||||||
|
*/
|
||||||
|
private static String[] getISO2Table(String table) {
|
||||||
|
int len = table.length() / 5;
|
||||||
|
String[] isoTable = new String[len];
|
||||||
|
for (int i = 0, j = 0; i < len; i++, j += 5) {
|
||||||
|
isoTable[i] = table.substring(j, j + 2);
|
||||||
|
}
|
||||||
|
return isoTable;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method computes a set of ISO3166-1 alpha-3 country codes from
|
* This method computes a set of ISO3166-1 alpha-3 country codes from
|
||||||
* existing isoCountryTable.
|
* existing isoCountryTable.
|
||||||
*/
|
*/
|
||||||
static Set<String> computeISO3166_1Alpha3Countries() {
|
private static Set<String> computeISO3166_1Alpha3Countries() {
|
||||||
int tableLength = isoCountryTable.length();
|
int tableLength = isoCountryTable.length();
|
||||||
String[] isoTable = new String[tableLength / 5];
|
String[] isoTable = new String[tableLength / 5];
|
||||||
for (int i = 0, index = 0; index < tableLength; i++, index += 5) {
|
for (int i = 0, index = 0; index < tableLength; i++, index += 5) {
|
||||||
@ -500,6 +578,5 @@ class LocaleISOData {
|
|||||||
return Set.of(isoTable);
|
return Set.of(isoTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LocaleISOData() {
|
private LocaleISOData() {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -38,6 +38,7 @@ import jdk.internal.util.StaticProperty;
|
|||||||
import jdk.internal.vm.annotation.Stable;
|
import jdk.internal.vm.annotation.Stable;
|
||||||
|
|
||||||
import java.util.StringJoiner;
|
import java.util.StringJoiner;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public final class BaseLocale {
|
public final class BaseLocale {
|
||||||
|
|
||||||
@ -90,6 +91,15 @@ public final class BaseLocale {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Interned BaseLocale cache
|
||||||
|
private static final Supplier<ReferencedKeySet<BaseLocale>> CACHE =
|
||||||
|
StableValue.supplier(new Supplier<>() {
|
||||||
|
@Override
|
||||||
|
public ReferencedKeySet<BaseLocale> get() {
|
||||||
|
return ReferencedKeySet.create(true, ReferencedKeySet.concurrentHashMapSupplier());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
public static final String SEP = "_";
|
public static final String SEP = "_";
|
||||||
|
|
||||||
private final String language;
|
private final String language;
|
||||||
@ -164,11 +174,7 @@ public final class BaseLocale {
|
|||||||
// Obtain the "interned" BaseLocale from the cache. The returned
|
// Obtain the "interned" BaseLocale from the cache. The returned
|
||||||
// "interned" instance can subsequently be used by the Locale
|
// "interned" instance can subsequently be used by the Locale
|
||||||
// instance which guarantees the locale components are properly cased/interned.
|
// instance which guarantees the locale components are properly cased/interned.
|
||||||
class InterningCache { // TODO: StableValue
|
return CACHE.get().intern(new BaseLocale(
|
||||||
private static final ReferencedKeySet<BaseLocale> CACHE =
|
|
||||||
ReferencedKeySet.create(true, ReferencedKeySet.concurrentHashMapSupplier());
|
|
||||||
}
|
|
||||||
return InterningCache.CACHE.intern(new BaseLocale(
|
|
||||||
language.intern(), // guaranteed to be lower-case
|
language.intern(), // guaranteed to be lower-case
|
||||||
LocaleUtils.toTitleString(script).intern(),
|
LocaleUtils.toTitleString(script).intern(),
|
||||||
region.intern(), // guaranteed to be upper-case
|
region.intern(), // guaranteed to be upper-case
|
||||||
|
Loading…
x
Reference in New Issue
Block a user