Home | History | Annotate | Download | only in text
      1 //  2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html#License
      3 /*
      4  *******************************************************************************
      5  * Copyright (C) 2008-2015, Google, International Business Machines Corporation and
      6  * others. All Rights Reserved.
      7  *******************************************************************************
      8  */
      9 package com.ibm.icu.text;
     10 
     11 import java.util.Arrays;
     12 import java.util.EnumSet;
     13 
     14 import com.ibm.icu.impl.StandardPlural;
     15 import com.ibm.icu.util.Freezable;
     16 import com.ibm.icu.util.Output;
     17 
     18 /**
     19  * Utility class for returning the plural category for a range of numbers, such as 15, so that appropriate messages can
     20  * be chosen. The rules for determining this value vary widely across locales.
     21  *
     22  * @author markdavis
     23  * @internal
     24  * @deprecated This API is ICU internal only.
     25  */
     26 @Deprecated
     27 public final class PluralRanges implements Freezable<PluralRanges>, Comparable<PluralRanges> {
     28 
     29     private volatile boolean isFrozen;
     30     private Matrix matrix = new Matrix();
     31     private boolean[] explicit = new boolean[StandardPlural.COUNT];
     32 
     33     /**
     34      * Constructor
     35      *
     36      * @internal
     37      * @deprecated This API is ICU internal only.
     38      */
     39     @Deprecated
     40     public PluralRanges() {
     41     }
     42 
     43     /**
     44      * Internal class for mapping from two StandardPluralCategories values to another.
     45      */
     46     private static final class Matrix implements Comparable<Matrix>, Cloneable {
     47         private byte[] data = new byte[StandardPlural.COUNT * StandardPlural.COUNT];
     48         {
     49             for (int i = 0; i < data.length; ++i) {
     50                 data[i] = -1;
     51             }
     52         }
     53 
     54         Matrix() {
     55         }
     56 
     57         /**
     58          * Internal method for setting.
     59          */
     60         @SuppressWarnings("unused")
     61         void set(StandardPlural start, StandardPlural end, StandardPlural result) {
     62             data[start.ordinal() * StandardPlural.COUNT + end.ordinal()] = result == null ? (byte) -1
     63                     : (byte) result.ordinal();
     64         }
     65 
     66         /**
     67          * Internal method for setting; throws exception if already set.
     68          */
     69         void setIfNew(StandardPlural start, StandardPlural end,
     70                 StandardPlural result) {
     71             byte old = data[start.ordinal() * StandardPlural.COUNT + end.ordinal()];
     72             if (old >= 0) {
     73                 throw new IllegalArgumentException("Previously set value for <" + start + ", " + end + ", "
     74                         + StandardPlural.VALUES.get(old) + ">");
     75             }
     76             data[start.ordinal() * StandardPlural.COUNT + end.ordinal()] = result == null ? (byte) -1
     77                     : (byte) result.ordinal();
     78         }
     79 
     80         /**
     81          * Internal method for getting.
     82          */
     83         StandardPlural get(StandardPlural start, StandardPlural end) {
     84             byte result = data[start.ordinal() * StandardPlural.COUNT + end.ordinal()];
     85             return result < 0 ? null : StandardPlural.VALUES.get(result);
     86         }
     87 
     88         /**
     89          * Internal method to see if <*,end> values are all the same.
     90          */
     91         @SuppressWarnings("unused")
     92         StandardPlural endSame(StandardPlural end) {
     93             StandardPlural first = null;
     94             for (StandardPlural start : StandardPlural.VALUES) {
     95                 StandardPlural item = get(start, end);
     96                 if (item == null) {
     97                     continue;
     98                 }
     99                 if (first == null) {
    100                     first = item;
    101                     continue;
    102                 }
    103                 if (first != item) {
    104                     return null;
    105                 }
    106             }
    107             return first;
    108         }
    109 
    110         /**
    111          * Internal method to see if <start,*> values are all the same.
    112          */
    113         @SuppressWarnings("unused")
    114         StandardPlural startSame(StandardPlural start,
    115                 EnumSet<StandardPlural> endDone, Output<Boolean> emit) {
    116             emit.value = false;
    117             StandardPlural first = null;
    118             for (StandardPlural end : StandardPlural.VALUES) {
    119                 StandardPlural item = get(start, end);
    120                 if (item == null) {
    121                     continue;
    122                 }
    123                 if (first == null) {
    124                     first = item;
    125                     continue;
    126                 }
    127                 if (first != item) {
    128                     return null;
    129                 }
    130                 // only emit if we didn't cover with the 'end' values
    131                 if (!endDone.contains(end)) {
    132                     emit.value = true;
    133                 }
    134             }
    135             return first;
    136         }
    137 
    138         @Override
    139         public int hashCode() {
    140             int result = 0;
    141             for (int i = 0; i < data.length; ++i) {
    142                 result = result * 37 + data[i];
    143             }
    144             return result;
    145         }
    146 
    147         @Override
    148         public boolean equals(Object other) {
    149             if (!(other instanceof Matrix)) {
    150                 return false;
    151             }
    152             return 0 == compareTo((Matrix) other);
    153         }
    154 
    155         @Override
    156         public int compareTo(Matrix o) {
    157             for (int i = 0; i < data.length; ++i) {
    158                 int diff = data[i] - o.data[i];
    159                 if (diff != 0) {
    160                     return diff;
    161                 }
    162             }
    163             return 0;
    164         }
    165 
    166         @Override
    167         public Matrix clone() {
    168             Matrix result = new Matrix();
    169             result.data = data.clone();
    170             return result;
    171         }
    172 
    173         @Override
    174         public String toString() {
    175             StringBuilder result = new StringBuilder();
    176             for (StandardPlural i : StandardPlural.values()) {
    177                 for (StandardPlural j : StandardPlural.values()) {
    178                     StandardPlural x = get(i, j);
    179                     if (x != null) {
    180                         result.append(i + " & " + j + "  " + x + ";\n");
    181                     }
    182                 }
    183             }
    184             return result.toString();
    185         }
    186     }
    187 
    188     /**
    189      * Internal method for building. If the start or end are null, it means everything of that type.
    190      *
    191      * @param rangeStart
    192      *            plural category for the start of the range
    193      * @param rangeEnd
    194      *            plural category for the end of the range
    195      * @param result
    196      *            the resulting plural category
    197      * @internal
    198      * @deprecated This API is ICU internal only.
    199      */
    200     @Deprecated
    201     public void add(StandardPlural rangeStart, StandardPlural rangeEnd,
    202             StandardPlural result) {
    203         if (isFrozen) {
    204             throw new UnsupportedOperationException();
    205         }
    206         explicit[result.ordinal()] = true;
    207         if (rangeStart == null) {
    208             for (StandardPlural rs : StandardPlural.values()) {
    209                 if (rangeEnd == null) {
    210                     for (StandardPlural re : StandardPlural.values()) {
    211                         matrix.setIfNew(rs, re, result);
    212                     }
    213                 } else {
    214                     explicit[rangeEnd.ordinal()] = true;
    215                     matrix.setIfNew(rs, rangeEnd, result);
    216                 }
    217             }
    218         } else if (rangeEnd == null) {
    219             explicit[rangeStart.ordinal()] = true;
    220             for (StandardPlural re : StandardPlural.values()) {
    221                 matrix.setIfNew(rangeStart, re, result);
    222             }
    223         } else {
    224             explicit[rangeStart.ordinal()] = true;
    225             explicit[rangeEnd.ordinal()] = true;
    226             matrix.setIfNew(rangeStart, rangeEnd, result);
    227         }
    228     }
    229 
    230     /**
    231      * Returns the appropriate plural category for a range from start to end. If there is no available data, then
    232      * 'end' is returned as an implicit value. (Such an implicit value can be tested for with {@link #isExplicit}.)
    233      *
    234      * @param start
    235      *            plural category for the start of the range
    236      * @param end
    237      *            plural category for the end of the range
    238      * @return the resulting plural category, or 'end' if there is no data.
    239      * @internal
    240      * @deprecated This API is ICU internal only.
    241      */
    242     @Deprecated
    243     public StandardPlural get(StandardPlural start, StandardPlural end) {
    244         StandardPlural result = matrix.get(start, end);
    245         return result == null ? end : result;
    246     }
    247 
    248     /**
    249      * Returns whether the appropriate plural category for a range from start to end
    250      * is explicitly in the data (vs given an implicit value). See also {@link #get}.
    251      *
    252      * @param start
    253      *            plural category for the start of the range
    254      * @param end
    255      *            plural category for the end of the range
    256      * @return whether the value for (start,end) is explicit or not.
    257      * @internal
    258      * @deprecated This API is ICU internal only.
    259      */
    260     @Deprecated
    261     public boolean isExplicit(StandardPlural start, StandardPlural end) {
    262         return matrix.get(start, end) != null;
    263     }
    264 
    265     /**
    266      * Internal method to determines whether the StandardPluralCategories was explicitly used in any add statement.
    267      *
    268      * @param count
    269      *            plural category to test
    270      * @return true if set
    271      * @internal
    272      * @deprecated This API is ICU internal only.
    273      */
    274     @Deprecated
    275     public boolean isExplicitlySet(StandardPlural count) {
    276         return explicit[count.ordinal()];
    277     }
    278 
    279     /**
    280      * {@inheritDoc}
    281      * @internal
    282      * @deprecated This API is ICU internal only.
    283      */
    284     @Deprecated
    285     @Override
    286     public boolean equals(Object other) {
    287         if (this == other) {
    288             return true;
    289         }
    290         if (!(other instanceof PluralRanges)) {
    291             return false;
    292         }
    293         PluralRanges otherPR = (PluralRanges)other;
    294         return matrix.equals(otherPR.matrix) && Arrays.equals(explicit, otherPR.explicit);
    295     }
    296 
    297     /**
    298      * {@inheritDoc}
    299      * @internal
    300      * @deprecated This API is ICU internal only.
    301      */
    302     @Override
    303     @Deprecated
    304     public int hashCode() {
    305         return matrix.hashCode();
    306     }
    307 
    308     /**
    309      * {@inheritDoc}
    310      * @internal
    311      * @deprecated This API is ICU internal only.
    312      */
    313     @Override
    314     @Deprecated
    315     public int compareTo(PluralRanges that) {
    316         return matrix.compareTo(that.matrix);
    317     }
    318 
    319     /**
    320      * {@inheritDoc}
    321      * @internal
    322      * @deprecated This API is ICU internal only.
    323      */
    324     @Override
    325     @Deprecated
    326     public boolean isFrozen() {
    327         return isFrozen;
    328     }
    329 
    330     /**
    331      * {@inheritDoc}
    332      * @internal
    333      * @deprecated This API is ICU internal only.
    334      */
    335     @Override
    336     @Deprecated
    337     public PluralRanges freeze() {
    338         isFrozen = true;
    339         return this;
    340     }
    341 
    342     /**
    343      * {@inheritDoc}
    344      * @internal
    345      * @deprecated This API is ICU internal only.
    346      */
    347     @Override
    348     @Deprecated
    349     public PluralRanges cloneAsThawed() {
    350         PluralRanges result = new PluralRanges();
    351         result.explicit = explicit.clone();
    352         result.matrix = matrix.clone();
    353         return result;
    354     }
    355 
    356     /**
    357      * {@inheritDoc}
    358      * @internal
    359      * @deprecated This API is ICU internal only.
    360      */
    361     @Override
    362     @Deprecated
    363     public String toString() {
    364         return matrix.toString();
    365     }
    366 }