]> git.saurik.com Git - apple/icu.git/blame - icuSources/common/pluralmap.h
ICU-57131.0.1.tar.gz
[apple/icu.git] / icuSources / common / pluralmap.h
CommitLineData
2ca993e8
A
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
17U_NAMESPACE_BEGIN
18
19class UnicodeString;
20
21class U_COMMON_API PluralMapBase : public UMemory {
22public:
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 */
69template<typename T>
70class PluralMap : public PluralMapBase {
71public:
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
254private:
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
288U_NAMESPACE_END
289
290#endif