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 */ PluralMap()75 PluralMap() : fOtherVariant() { 76 initializeNew(); 77 } 78 79 /** 80 * Other category is mapped to otherVariant. 81 */ PluralMap(const T & otherVariant)82 PluralMap(const T &otherVariant) : fOtherVariant(otherVariant) { 83 initializeNew(); 84 } 85 PluralMap(const PluralMap<T> & other)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 ~PluralMap()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 */ clear()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 */ next(Category & index)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 */ nextMutable(Category & index)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 */ getOther()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 */ get(Category v)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 */ get(const char * category)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 */ get(const UnicodeString & category)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 */ getMutable(Category category,UErrorCode & status)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 */ getMutable(const char * category,UErrorCode & status)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 */ getMutableWithDefault(Category category,const T & defaultValue,UErrorCode & status)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 */ equals(const PluralMap<T> & rhs,UBool (* eqFunc)(const T &,const T &))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 getMutable(Category category,const T * defaultValue,UErrorCode & status)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 initializeNew()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