xref: /aosp_15_r20/external/icu/icu4c/source/common/pluralmap.h (revision 0e209d3975ff4a8c132096b14b0e9364a753506e)
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