blob: 712a167d5ac0cd9ae51868629a2f65df77d67c8e [file] [log] [blame]
/*
*******************************************************************************
* Copyright (C) 2015-2016, International Business Machines Corporation and
* others. All Rights Reserved.
*******************************************************************************
*/
package com.ibm.icu.impl;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import com.ibm.icu.impl.locale.AsciiUtil;
import com.ibm.icu.util.UResourceBundle;
import com.ibm.icu.util.UResourceBundleIterator;
/**
* @author markdavis
*
*/
public class ValidIdentifiers {
public enum Datatype {
currency,
language,
region,
script,
subdivision,
unit,
variant,
u,
t,
x,
illegal
}
public enum Datasubtype {
deprecated,
private_use,
regular,
special,
unknown,
macroregion,
}
public static class ValiditySet {
public final Set<String> regularData;
public final Map<String,Set<String>> subdivisionData;
public ValiditySet(Set<String> plainData, boolean makeMap) {
if (makeMap) {
HashMap<String,Set<String>> _subdivisionData = new HashMap<String,Set<String>>();
for (String s : plainData) {
int pos = s.indexOf('-'); // read v28 data also
int pos2 = pos+1;
if (pos < 0) {
pos2 = pos = s.charAt(0) < 'A' ? 3 : 2;
}
final String key = s.substring(0, pos);
final String subdivision = s.substring(pos2);
Set<String> oldSet = _subdivisionData.get(key);
if (oldSet == null) {
_subdivisionData.put(key, oldSet = new HashSet<String>());
}
oldSet.add(subdivision);
}
this.regularData = null;
HashMap<String,Set<String>> _subdivisionData2 = new HashMap<String,Set<String>>();
// protect the sets
for (Entry<String, Set<String>> e : _subdivisionData.entrySet()) {
Set<String> value = e.getValue();
// optimize a bit by using singleton
Set<String> set = value.size() == 1 ? Collections.singleton(value.iterator().next())
: Collections.unmodifiableSet(value);
_subdivisionData2.put(e.getKey(), set);
}
this.subdivisionData = Collections.unmodifiableMap(_subdivisionData2);
} else {
this.regularData = Collections.unmodifiableSet(plainData);
this.subdivisionData = null;
}
}
public boolean contains(String code) {
if (regularData != null) {
return regularData.contains(code);
} else {
int pos = code.indexOf('-');
String key = code.substring(0,pos);
final String value = code.substring(pos+1);
return contains(key, value);
}
}
public boolean contains(String key, String value) {
Set<String> oldSet = subdivisionData.get(key);
return oldSet != null && oldSet.contains(value);
}
@Override
public String toString() {
if (regularData != null) {
return regularData.toString();
} else {
return subdivisionData.toString();
}
}
}
private static class ValidityData {
static final Map<Datatype,Map<Datasubtype,ValiditySet>> data;
static {
Map<Datatype, Map<Datasubtype, ValiditySet>> _data = new EnumMap<Datatype,Map<Datasubtype,ValiditySet>>(Datatype.class);
UResourceBundle suppData = UResourceBundle.getBundleInstance(
ICUResourceBundle.ICU_BASE_NAME,
"supplementalData",
ICUResourceBundle.ICU_DATA_CLASS_LOADER);
UResourceBundle validityInfo = suppData.get("idValidity");
for(UResourceBundleIterator datatypeIterator = validityInfo.getIterator();
datatypeIterator.hasNext();) {
UResourceBundle datatype = datatypeIterator.next();
String rawKey = datatype.getKey();
Datatype key = Datatype.valueOf(rawKey);
Map<Datasubtype,ValiditySet> values = new EnumMap<Datasubtype,ValiditySet>(Datasubtype.class);
for(UResourceBundleIterator datasubtypeIterator = datatype.getIterator();
datasubtypeIterator.hasNext();) {
UResourceBundle datasubtype = datasubtypeIterator.next();
String rawsubkey = datasubtype.getKey();
Datasubtype subkey = Datasubtype.valueOf(rawsubkey);
// handle single value specially
Set<String> subvalues = new HashSet<String>();
if (datasubtype.getType() == UResourceBundle.STRING) {
addRange(datasubtype.getString(), subvalues);
} else {
for (String string : datasubtype.getStringArray()) {
addRange(string, subvalues);
}
}
values.put(subkey, new ValiditySet(subvalues, key == Datatype.subdivision));
}
_data.put(key, Collections.unmodifiableMap(values));
}
data = Collections.unmodifiableMap(_data);
}
private static void addRange(String string, Set<String> subvalues) {
string = AsciiUtil.toLowerString(string);
int pos = string.indexOf('~');
if (pos < 0) {
subvalues.add(string);
} else {
StringRange.expand(string.substring(0,pos), string.substring(pos+1), false, subvalues);
}
}
}
public static Map<Datatype, Map<Datasubtype, ValiditySet>> getData() {
return ValidityData.data;
}
/**
* Returns the Datasubtype containing the code, or null if there is none.
*/
public static Datasubtype isValid(Datatype datatype, Set<Datasubtype> datasubtypes, String code) {
Map<Datasubtype, ValiditySet> subtable = ValidityData.data.get(datatype);
if (subtable != null) {
for (Datasubtype datasubtype : datasubtypes) {
ValiditySet validitySet = subtable.get(datasubtype);
if (validitySet != null) {
if (validitySet.contains(AsciiUtil.toLowerString(code))) {
return datasubtype;
}
}
}
}
return null;
}
public static Datasubtype isValid(Datatype datatype, Set<Datasubtype> datasubtypes, String code, String value) {
Map<Datasubtype, ValiditySet> subtable = ValidityData.data.get(datatype);
if (subtable != null) {
code = AsciiUtil.toLowerString(code);
value = AsciiUtil.toLowerString(value);
for (Datasubtype datasubtype : datasubtypes) {
ValiditySet validitySet = subtable.get(datasubtype);
if (validitySet != null) {
if (validitySet.contains(code, value)) {
return datasubtype;
}
}
}
}
return null;
}
}