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