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