1313import com .google .common .collect .Multimap ;
1414import com .google .common .collect .Sets ;
1515import com .google .common .collect .TreeMultimap ;
16+ import com .ibm .icu .impl .Row ;
1617import com .ibm .icu .impl .Row .R2 ;
18+ import com .ibm .icu .impl .Row .R4 ;
1719import com .ibm .icu .lang .UCharacter ;
1820import com .ibm .icu .number .UnlocalizedNumberFormatter ;
1921import com .ibm .icu .text .PluralRules ;
2931import java .util .Collections ;
3032import java .util .Comparator ;
3133import java .util .EnumSet ;
34+ import java .util .HashSet ;
3235import java .util .Iterator ;
3336import java .util .LinkedHashMap ;
3437import java .util .LinkedHashSet ;
4851import org .unicode .cldr .util .GrammarInfo .GrammaticalFeature ;
4952import org .unicode .cldr .util .Rational .FormatStyle ;
5053import org .unicode .cldr .util .Rational .RationalParser ;
54+ import org .unicode .cldr .util .StandardCodes .LstrType ;
5155import org .unicode .cldr .util .SupplementalDataInfo .PluralInfo ;
56+ import org .unicode .cldr .util .Validity .Status ;
5257
5358public class UnitConverter implements Freezable <UnitConverter > {
5459 public static boolean DEBUG = false ;
@@ -80,7 +85,7 @@ public class UnitConverter implements Freezable<UnitConverter> {
8085 private Multimap <String , UnitSystem > sourceToSystems = TreeMultimap .create ();
8186 private Set <String > baseUnits ;
8287 private Multimap <String , Continuation > continuations = TreeMultimap .create ();
83- private Comparator <String > quantityComparator ;
88+ private MapComparator <String > quantityComparator ;
8489
8590 private Map <String , String > fixDenormalized ;
8691 private ImmutableMap <String , UnitId > idToUnitId ;
@@ -92,6 +97,17 @@ public class UnitConverter implements Freezable<UnitConverter> {
9297
9398 public TargetInfoComparator targetInfoComparator ;
9499
100+ private final MapComparator <String > LongUnitIdOrder = new MapComparator <>();
101+ private final MapComparator <String > ShortUnitIdOrder = new MapComparator <>();
102+
103+ public Comparator <String > getLongUnitIdComparator () {
104+ return LongUnitIdOrder ;
105+ }
106+
107+ public Comparator <String > getShortUnitIdComparator () {
108+ return ShortUnitIdOrder ;
109+ }
110+
95111 /** Warning: ordering is important; determines the normalized output */
96112 public static final Set <String > BASE_UNITS =
97113 ImmutableSet .of (
@@ -198,6 +214,74 @@ public UnitConverter freeze() {
198214 }
199215 }
200216 idToUnitId = ImmutableMap .copyOf (_idToUnitId );
217+
218+ // build the map comparators
219+
220+ Set <R4 <Integer , UnitSystem , Rational , String >> all = new TreeSet <>();
221+ Set <String > baseSeen = new HashSet <>();
222+ for (String longUnit :
223+ Validity .getInstance ().getStatusToCodes (LstrType .unit ).get (Status .regular )) {
224+ Output <String > base = new Output <>();
225+ String shortUnit = getShortId (longUnit );
226+ ConversionInfo conversionInfo = parseUnitId (shortUnit , base , false );
227+ if (conversionInfo == null ) {
228+ if (longUnit .equals ("temperature-generic" )) {
229+ conversionInfo = parseUnitId ("kelvin" , base , false );
230+ }
231+ }
232+ String quantity = getQuantityFromUnit (base .value , false );
233+ Integer quantityNumericOrder = quantityComparator .getNumericOrder (quantity );
234+ if (quantityNumericOrder == null ) { // try the inverse
235+ if (base .value .equals ("meter-per-cubic-meter" )) { // HACK
236+ quantityNumericOrder = quantityComparator .getNumericOrder ("consumption" );
237+ }
238+ if (quantityNumericOrder == null ) {
239+ throw new IllegalArgumentException (
240+ "Missing quantity for: " + base .value + ", " + shortUnit );
241+ }
242+ }
243+
244+ final EnumSet <UnitSystem > systems = EnumSet .copyOf (getSystemsEnum (shortUnit ));
245+
246+ // to sort the right items together items together, put together a sort key
247+ UnitSystem sortingSystem = systems .iterator ().next ();
248+ switch (sortingSystem ) {
249+ case metric :
250+ case si :
251+ case si_acceptable :
252+ case astronomical :
253+ case metric_adjacent :
254+ case person_age :
255+ sortingSystem = UnitSystem .metric ;
256+ break ;
257+ // country specific
258+ case other :
259+ case ussystem :
260+ case uksystem :
261+ case jpsystem :
262+ sortingSystem = UnitSystem .other ;
263+ break ;
264+ default :
265+ throw new IllegalArgumentException (
266+ "Add new unitSystem to a grouping: " + sortingSystem );
267+ }
268+ R4 <Integer , UnitSystem , Rational , String > sortKey =
269+ Row .of (
270+ quantityNumericOrder ,
271+ sortingSystem ,
272+ conversionInfo .factor ,
273+ shortUnit );
274+ all .add (sortKey );
275+ }
276+ LongUnitIdOrder .setErrorOnMissing (true );
277+ ShortUnitIdOrder .setErrorOnMissing (true );
278+ for (R4 <Integer , UnitSystem , Rational , String > item : all ) {
279+ String shortId = item .get3 ();
280+ ShortUnitIdOrder .add (shortId );
281+ LongUnitIdOrder .add (getLongId (shortId ));
282+ }
283+ LongUnitIdOrder .freeze ();
284+ ShortUnitIdOrder .freeze ();
201285 }
202286 return this ;
203287 }
@@ -649,7 +733,7 @@ private void addToSourceToTarget(
649733 }
650734 }
651735
652- private Comparator <String > getQuantityComparator (
736+ private MapComparator <String > getQuantityComparator (
653737 Map <String , String > baseUnitToQuantity2 , Map <String , String > baseUnitToStatus2 ) {
654738 // We want to sort all the quantities so that we have a natural ordering within compound
655739 // units. So kilowatt-hour, not hour-kilowatt.
0 commit comments