Line data Source code
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 0 : 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 0 : PluralMap() : fOtherVariant() {
78 0 : initializeNew();
79 0 : }
80 :
81 : /**
82 : * Other category is mapped to otherVariant.
83 : */
84 0 : PluralMap(const T &otherVariant) : fOtherVariant(otherVariant) {
85 0 : initializeNew();
86 0 : }
87 :
88 0 : PluralMap(const PluralMap<T> &other) : fOtherVariant(other.fOtherVariant) {
89 0 : fVariants[0] = &fOtherVariant;
90 0 : for (int32_t i = 1; i < UPRV_LENGTHOF(fVariants); ++i) {
91 0 : fVariants[i] = other.fVariants[i] ?
92 0 : new T(*other.fVariants[i]) : NULL;
93 : }
94 0 : }
95 :
96 0 : PluralMap<T> &operator=(const PluralMap<T> &other) {
97 0 : if (this == &other) {
98 0 : return *this;
99 : }
100 0 : for (int32_t i = 0; i < UPRV_LENGTHOF(fVariants); ++i) {
101 0 : if (fVariants[i] != NULL && other.fVariants[i] != NULL) {
102 0 : *fVariants[i] = *other.fVariants[i];
103 0 : } else if (fVariants[i] != NULL) {
104 0 : delete fVariants[i];
105 0 : fVariants[i] = NULL;
106 0 : } else if (other.fVariants[i] != NULL) {
107 0 : fVariants[i] = new T(*other.fVariants[i]);
108 : } else {
109 : // do nothing
110 : }
111 : }
112 0 : return *this;
113 : }
114 :
115 0 : ~PluralMap() {
116 0 : for (int32_t i = 1; i < UPRV_LENGTHOF(fVariants); ++i) {
117 0 : delete fVariants[i];
118 : }
119 0 : }
120 :
121 : /**
122 : * Removes all mappings and makes 'other' point to the default value.
123 : */
124 0 : void clear() {
125 0 : *fVariants[0] = T();
126 0 : for (int32_t i = 1; i < UPRV_LENGTHOF(fVariants); ++i) {
127 0 : delete fVariants[i];
128 0 : fVariants[i] = NULL;
129 : }
130 0 : }
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 0 : const T *next(Category &index) const {
140 0 : int32_t idx = index;
141 0 : ++idx;
142 0 : for (; idx < UPRV_LENGTHOF(fVariants); ++idx) {
143 0 : if (fVariants[idx] != NULL) {
144 0 : index = static_cast<Category>(idx);
145 0 : return fVariants[idx];
146 : }
147 : }
148 0 : index = static_cast<Category>(idx);
149 0 : return NULL;
150 : }
151 :
152 : /**
153 : * non const version of next.
154 : */
155 0 : T *nextMutable(Category &index) {
156 0 : const T *result = next(index);
157 0 : return const_cast<T *>(result);
158 : }
159 :
160 : /**
161 : * Returns the 'other' variant.
162 : * Same as calling get(OTHER).
163 : */
164 0 : const T &getOther() const {
165 0 : 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 0 : const T &get(Category v) const {
174 0 : int32_t index = v;
175 0 : if (index < 0 || index >= UPRV_LENGTHOF(fVariants) || fVariants[index] == NULL) {
176 0 : return *fVariants[0];
177 : }
178 0 : 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 0 : const T &get(const char *category) const {
186 0 : 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 0 : const T &get(const UnicodeString &category) const {
194 0 : 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 0 : T *getMutable(
208 : Category category,
209 : UErrorCode &status) {
210 0 : 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 0 : T *getMutable(
219 : const char *category,
220 : UErrorCode &status) {
221 0 : 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 0 : T *getMutableWithDefault(
230 : Category category,
231 : const T &defaultValue,
232 : UErrorCode &status) {
233 0 : return getMutable(category, &defaultValue, status);
234 : }
235 :
236 : /**
237 : * Returns TRUE if this object equals rhs.
238 : */
239 0 : UBool equals(
240 : const PluralMap<T> &rhs,
241 : UBool (*eqFunc)(const T &, const T &)) const {
242 0 : for (int32_t i = 0; i < UPRV_LENGTHOF(fVariants); ++i) {
243 0 : if (fVariants[i] == rhs.fVariants[i]) {
244 0 : continue;
245 : }
246 0 : if (fVariants[i] == NULL || rhs.fVariants[i] == NULL) {
247 0 : return FALSE;
248 : }
249 0 : if (!eqFunc(*fVariants[i], *rhs.fVariants[i])) {
250 0 : return FALSE;
251 : }
252 : }
253 0 : return TRUE;
254 : }
255 :
256 : private:
257 : T fOtherVariant;
258 : T* fVariants[6];
259 :
260 0 : T *getMutable(
261 : Category category,
262 : const T *defaultValue,
263 : UErrorCode &status) {
264 0 : if (U_FAILURE(status)) {
265 0 : return NULL;
266 : }
267 0 : int32_t index = category;
268 0 : if (index < 0 || index >= UPRV_LENGTHOF(fVariants)) {
269 0 : status = U_ILLEGAL_ARGUMENT_ERROR;
270 0 : return NULL;
271 : }
272 0 : if (fVariants[index] == NULL) {
273 0 : fVariants[index] = defaultValue == NULL ?
274 0 : new T() : new T(*defaultValue);
275 : }
276 0 : if (!fVariants[index]) {
277 0 : status = U_MEMORY_ALLOCATION_ERROR;
278 : }
279 0 : return fVariants[index];
280 : }
281 :
282 0 : void initializeNew() {
283 0 : fVariants[0] = &fOtherVariant;
284 0 : for (int32_t i = 1; i < UPRV_LENGTHOF(fVariants); ++i) {
285 0 : fVariants[i] = NULL;
286 : }
287 0 : }
288 : };
289 :
290 : U_NAMESPACE_END
291 :
292 : #endif
|