• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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