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