OLD | NEW |
(Empty) | |
| 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 |
OLD | NEW |