Home | History | Annotate | Download | only in common
      1 //  2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 ******************************************************************************
      5 * Copyright (C) 2015, International Business Machines Corporation and
      6 * others. All Rights Reserved.
      7 ******************************************************************************
      8 *
      9 * File pluralmap.h - PluralMap class that maps plural categories to values.
     10 ******************************************************************************
     11 */
     12 
     13 #ifndef __PLURAL_MAP_H__
     14 #define __PLURAL_MAP_H__
     15 
     16 #include "unicode/uobject.h"
     17 #include "cmemory.h"
     18 
     19 U_NAMESPACE_BEGIN
     20 
     21 class UnicodeString;
     22 
     23 class U_COMMON_API PluralMapBase : public UMemory {
     24 public:
     25     /**
     26      * The names of all the plural categories. NONE is not an actual plural
     27      * category, but rather represents the absense of a plural category.
     28      */
     29     enum Category {
     30         NONE = -1,
     31         OTHER,
     32         ZERO,
     33         ONE,
     34         TWO,
     35         FEW,
     36         MANY,
     37         CATEGORY_COUNT
     38     };
     39 
     40     /**
     41      * Converts a category name such as "zero", "one", "two", "few", "many"
     42      * or "other" to a category enum. Returns NONE for an unrecognized
     43      * category name.
     44      */
     45     static Category toCategory(const char *categoryName);
     46 
     47     /**
     48      * Converts a category name such as "zero", "one", "two", "few", "many"
     49      * or "other" to a category enum.  Returns NONE for urecongized
     50      * category name.
     51      */
     52     static Category toCategory(const UnicodeString &categoryName);
     53 
     54     /**
     55      * Converts a category to a name.
     56      * Passing NONE or CATEGORY_COUNT for category returns NULL.
     57      */
     58     static const char *getCategoryName(Category category);
     59 };
     60 
     61 /**
     62  * A Map of plural categories to values. It maintains ownership of the
     63  * values.
     64  *
     65  * Type T is the value type. T must provide the followng:
     66  * 1) Default constructor
     67  * 2) Copy constructor
     68  * 3) Assignment operator
     69  * 4) Must extend UMemory
     70  */
     71 template<typename T>
     72 class PluralMap : public PluralMapBase {
     73 public:
     74     /**
     75      * Other category is maps to a copy of the default value.
     76      */
     77     PluralMap() : fOtherVariant() {
     78         initializeNew();
     79     }
     80 
     81     /**
     82      * Other category is mapped to otherVariant.
     83      */
     84     PluralMap(const T &otherVariant) : fOtherVariant(otherVariant) {
     85         initializeNew();
     86     }
     87 
     88     PluralMap(const PluralMap<T> &other) : fOtherVariant(other.fOtherVariant) {
     89         fVariants[0] = &fOtherVariant;
     90         for (int32_t i = 1; i < UPRV_LENGTHOF(fVariants); ++i) {
     91             fVariants[i] = other.fVariants[i] ?
     92                     new T(*other.fVariants[i]) : NULL;
     93         }
     94     }
     95 
     96     PluralMap<T> &operator=(const PluralMap<T> &other) {
     97         if (this == &other) {
     98             return *this;
     99         }
    100         for (int32_t i = 0; i < UPRV_LENGTHOF(fVariants); ++i) {
    101             if (fVariants[i] != NULL && other.fVariants[i] != NULL) {
    102                 *fVariants[i] = *other.fVariants[i];
    103             } else if (fVariants[i] != NULL) {
    104                 delete fVariants[i];
    105                 fVariants[i] = NULL;
    106             } else if (other.fVariants[i] != NULL) {
    107                 fVariants[i] = new T(*other.fVariants[i]);
    108             } else {
    109                 // do nothing
    110             }
    111         }
    112         return *this;
    113     }
    114 
    115     ~PluralMap() {
    116         for (int32_t i = 1; i < UPRV_LENGTHOF(fVariants); ++i) {
    117             delete fVariants[i];
    118         }
    119     }
    120 
    121     /**
    122      * Removes all mappings and makes 'other' point to the default value.
    123      */
    124     void clear() {
    125         *fVariants[0] = T();
    126         for (int32_t i = 1; i < UPRV_LENGTHOF(fVariants); ++i) {
    127             delete fVariants[i];
    128             fVariants[i] = NULL;
    129         }
    130     }
    131 
    132     /**
    133      * Iterates through the mappings in this instance, set index to NONE
    134      * prior to using. Call next repeatedly to get the values until it
    135      * returns NULL. Each time next returns, caller may pass index
    136      * to getCategoryName() to get the name of the plural category.
    137      * When this function returns NULL, index is CATEGORY_COUNT
    138      */
    139     const T *next(Category &index) const {
    140         int32_t idx = index;
    141         ++idx;
    142         for (; idx < UPRV_LENGTHOF(fVariants); ++idx) {
    143             if (fVariants[idx] != NULL) {
    144                 index = static_cast<Category>(idx);
    145                 return fVariants[idx];
    146             }
    147         }
    148         index = static_cast<Category>(idx);
    149         return NULL;
    150     }
    151 
    152     /**
    153      * non const version of next.
    154      */
    155     T *nextMutable(Category &index) {
    156         const T *result = next(index);
    157         return const_cast<T *>(result);
    158     }
    159 
    160     /**
    161      * Returns the 'other' variant.
    162      * Same as calling get(OTHER).
    163      */
    164     const T &getOther() const {
    165         return get(OTHER);
    166     }
    167 
    168     /**
    169      * Returns the value associated with a category.
    170      * If no value found, or v is NONE or CATEGORY_COUNT, falls
    171      * back to returning the value for the 'other' category.
    172      */
    173     const T &get(Category v) const {
    174         int32_t index = v;
    175         if (index < 0 || index >= UPRV_LENGTHOF(fVariants) || fVariants[index] == NULL) {
    176             return *fVariants[0];
    177         }
    178         return *fVariants[index];
    179     }
    180 
    181     /**
    182      * Convenience routine to get the value by category name. Otherwise
    183      * works just like get(Category).
    184      */
    185     const T &get(const char *category) const {
    186         return get(toCategory(category));
    187     }
    188 
    189     /**
    190      * Convenience routine to get the value by category name as a
    191      * UnicodeString. Otherwise works just like get(category).
    192      */
    193     const T &get(const UnicodeString &category) const {
    194         return get(toCategory(category));
    195     }
    196 
    197     /**
    198      * Returns a pointer to the value associated with a category
    199      * that caller can safely modify. If the value was defaulting to the 'other'
    200      * variant because no explicit value was stored, this method creates a
    201      * new value using the default constructor at the returned pointer.
    202      *
    203      * @param category the category with the value to change.
    204      * @param status error returned here if index is NONE or CATEGORY_COUNT
    205      *  or memory could not be allocated, or any other error happens.
    206      */
    207     T *getMutable(
    208             Category category,
    209             UErrorCode &status) {
    210         return getMutable(category, NULL, status);
    211     }
    212 
    213     /**
    214      * Convenience routine to get a mutable pointer to a value by category name.
    215      * Otherwise works just like getMutable(Category, UErrorCode &).
    216      * reports an error if the category name is invalid.
    217      */
    218     T *getMutable(
    219             const char *category,
    220             UErrorCode &status) {
    221         return getMutable(toCategory(category), NULL, status);
    222     }
    223 
    224     /**
    225      * Just like getMutable(Category, UErrorCode &) but copies defaultValue to
    226      * returned pointer if it was defaulting to the 'other' variant
    227      * because no explicit value was stored.
    228      */
    229     T *getMutableWithDefault(
    230             Category category,
    231             const T &defaultValue,
    232             UErrorCode &status) {
    233         return getMutable(category, &defaultValue, status);
    234     }
    235 
    236     /**
    237      * Returns TRUE if this object equals rhs.
    238      */
    239     UBool equals(
    240             const PluralMap<T> &rhs,
    241             UBool (*eqFunc)(const T &, const T &)) const {
    242         for (int32_t i = 0; i < UPRV_LENGTHOF(fVariants); ++i) {
    243             if (fVariants[i] == rhs.fVariants[i]) {
    244                 continue;
    245             }
    246             if (fVariants[i] == NULL || rhs.fVariants[i] == NULL) {
    247                 return FALSE;
    248             }
    249             if (!eqFunc(*fVariants[i], *rhs.fVariants[i])) {
    250                 return FALSE;
    251             }
    252         }
    253         return TRUE;
    254     }
    255 
    256 private:
    257     T fOtherVariant;
    258     T* fVariants[6];
    259 
    260     T *getMutable(
    261             Category category,
    262             const T *defaultValue,
    263             UErrorCode &status) {
    264         if (U_FAILURE(status)) {
    265             return NULL;
    266         }
    267         int32_t index = category;
    268         if (index < 0 || index >= UPRV_LENGTHOF(fVariants)) {
    269             status = U_ILLEGAL_ARGUMENT_ERROR;
    270             return NULL;
    271         }
    272         if (fVariants[index] == NULL) {
    273             fVariants[index] = defaultValue == NULL ?
    274                     new T() : new T(*defaultValue);
    275         }
    276         if (!fVariants[index]) {
    277             status = U_MEMORY_ALLOCATION_ERROR;
    278         }
    279         return fVariants[index];
    280     }
    281 
    282     void initializeNew() {
    283         fVariants[0] = &fOtherVariant;
    284         for (int32_t i = 1; i < UPRV_LENGTHOF(fVariants); ++i) {
    285             fVariants[i] = NULL;
    286         }
    287     }
    288 };
    289 
    290 U_NAMESPACE_END
    291 
    292 #endif
    293