Index: source/common/pluralmap.h |
diff --git a/source/common/pluralmap.h b/source/common/pluralmap.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..63ccf8d31d14f9b016aab65dfe4d1d7256f46097 |
--- /dev/null |
+++ b/source/common/pluralmap.h |
@@ -0,0 +1,290 @@ |
+/* |
+****************************************************************************** |
+* Copyright (C) 2015, International Business Machines Corporation and |
+* others. All Rights Reserved. |
+****************************************************************************** |
+* |
+* File pluralmap.h - PluralMap class that maps plural categories to values. |
+****************************************************************************** |
+*/ |
+ |
+#ifndef __PLURAL_MAP_H__ |
+#define __PLURAL_MAP_H__ |
+ |
+#include "unicode/uobject.h" |
+#include "cmemory.h" |
+ |
+U_NAMESPACE_BEGIN |
+ |
+class UnicodeString; |
+ |
+class U_COMMON_API PluralMapBase : public UMemory { |
+public: |
+ /** |
+ * The names of all the plural categories. NONE is not an actual plural |
+ * category, but rather represents the absense of a plural category. |
+ */ |
+ enum Category { |
+ NONE = -1, |
+ OTHER, |
+ ZERO, |
+ ONE, |
+ TWO, |
+ FEW, |
+ MANY, |
+ CATEGORY_COUNT |
+ }; |
+ |
+ /** |
+ * Converts a category name such as "zero", "one", "two", "few", "many" |
+ * or "other" to a category enum. Returns NONE for an unrecognized |
+ * category name. |
+ */ |
+ static Category toCategory(const char *categoryName); |
+ |
+ /** |
+ * Converts a category name such as "zero", "one", "two", "few", "many" |
+ * or "other" to a category enum. Returns NONE for urecongized |
+ * category name. |
+ */ |
+ static Category toCategory(const UnicodeString &categoryName); |
+ |
+ /** |
+ * Converts a category to a name. |
+ * Passing NONE or CATEGORY_COUNT for category returns NULL. |
+ */ |
+ static const char *getCategoryName(Category category); |
+}; |
+ |
+/** |
+ * A Map of plural categories to values. It maintains ownership of the |
+ * values. |
+ * |
+ * Type T is the value type. T must provide the followng: |
+ * 1) Default constructor |
+ * 2) Copy constructor |
+ * 3) Assignment operator |
+ * 4) Must extend UMemory |
+ */ |
+template<typename T> |
+class PluralMap : public PluralMapBase { |
+public: |
+ /** |
+ * Other category is maps to a copy of the default value. |
+ */ |
+ PluralMap() : fOtherVariant() { |
+ initializeNew(); |
+ } |
+ |
+ /** |
+ * Other category is mapped to otherVariant. |
+ */ |
+ PluralMap(const T &otherVariant) : fOtherVariant(otherVariant) { |
+ initializeNew(); |
+ } |
+ |
+ PluralMap(const PluralMap<T> &other) : fOtherVariant(other.fOtherVariant) { |
+ fVariants[0] = &fOtherVariant; |
+ for (int32_t i = 1; i < UPRV_LENGTHOF(fVariants); ++i) { |
+ fVariants[i] = other.fVariants[i] ? |
+ new T(*other.fVariants[i]) : NULL; |
+ } |
+ } |
+ |
+ PluralMap<T> &operator=(const PluralMap<T> &other) { |
+ if (this == &other) { |
+ return *this; |
+ } |
+ for (int32_t i = 0; i < UPRV_LENGTHOF(fVariants); ++i) { |
+ if (fVariants[i] != NULL && other.fVariants[i] != NULL) { |
+ *fVariants[i] = *other.fVariants[i]; |
+ } else if (fVariants[i] != NULL) { |
+ delete fVariants[i]; |
+ fVariants[i] = NULL; |
+ } else if (other.fVariants[i] != NULL) { |
+ fVariants[i] = new T(*other.fVariants[i]); |
+ } else { |
+ // do nothing |
+ } |
+ } |
+ return *this; |
+ } |
+ |
+ ~PluralMap() { |
+ for (int32_t i = 1; i < UPRV_LENGTHOF(fVariants); ++i) { |
+ delete fVariants[i]; |
+ } |
+ } |
+ |
+ /** |
+ * Removes all mappings and makes 'other' point to the default value. |
+ */ |
+ void clear() { |
+ *fVariants[0] = T(); |
+ for (int32_t i = 1; i < UPRV_LENGTHOF(fVariants); ++i) { |
+ delete fVariants[i]; |
+ fVariants[i] = NULL; |
+ } |
+ } |
+ |
+ /** |
+ * Iterates through the mappings in this instance, set index to NONE |
+ * prior to using. Call next repeatedly to get the values until it |
+ * returns NULL. Each time next returns, caller may pass index |
+ * to getCategoryName() to get the name of the plural category. |
+ * When this function returns NULL, index is CATEGORY_COUNT |
+ */ |
+ const T *next(Category &index) const { |
+ int32_t idx = index; |
+ ++idx; |
+ for (; idx < UPRV_LENGTHOF(fVariants); ++idx) { |
+ if (fVariants[idx] != NULL) { |
+ index = static_cast<Category>(idx); |
+ return fVariants[idx]; |
+ } |
+ } |
+ index = static_cast<Category>(idx); |
+ return NULL; |
+ } |
+ |
+ /** |
+ * non const version of next. |
+ */ |
+ T *nextMutable(Category &index) { |
+ const T *result = next(index); |
+ return const_cast<T *>(result); |
+ } |
+ |
+ /** |
+ * Returns the 'other' variant. |
+ * Same as calling get(OTHER). |
+ */ |
+ const T &getOther() const { |
+ return get(OTHER); |
+ } |
+ |
+ /** |
+ * Returns the value associated with a category. |
+ * If no value found, or v is NONE or CATEGORY_COUNT, falls |
+ * back to returning the value for the 'other' category. |
+ */ |
+ const T &get(Category v) const { |
+ int32_t index = v; |
+ if (index < 0 || index >= UPRV_LENGTHOF(fVariants) || fVariants[index] == NULL) { |
+ return *fVariants[0]; |
+ } |
+ return *fVariants[index]; |
+ } |
+ |
+ /** |
+ * Convenience routine to get the value by category name. Otherwise |
+ * works just like get(Category). |
+ */ |
+ const T &get(const char *category) const { |
+ return get(toCategory(category)); |
+ } |
+ |
+ /** |
+ * Convenience routine to get the value by category name as a |
+ * UnicodeString. Otherwise works just like get(category). |
+ */ |
+ const T &get(const UnicodeString &category) const { |
+ return get(toCategory(category)); |
+ } |
+ |
+ /** |
+ * Returns a pointer to the value associated with a category |
+ * that caller can safely modify. If the value was defaulting to the 'other' |
+ * variant because no explicit value was stored, this method creates a |
+ * new value using the default constructor at the returned pointer. |
+ * |
+ * @param category the category with the value to change. |
+ * @param status error returned here if index is NONE or CATEGORY_COUNT |
+ * or memory could not be allocated, or any other error happens. |
+ */ |
+ T *getMutable( |
+ Category category, |
+ UErrorCode &status) { |
+ return getMutable(category, NULL, status); |
+ } |
+ |
+ /** |
+ * Convenience routine to get a mutable pointer to a value by category name. |
+ * Otherwise works just like getMutable(Category, UErrorCode &). |
+ * reports an error if the category name is invalid. |
+ */ |
+ T *getMutable( |
+ const char *category, |
+ UErrorCode &status) { |
+ return getMutable(toCategory(category), NULL, status); |
+ } |
+ |
+ /** |
+ * Just like getMutable(Category, UErrorCode &) but copies defaultValue to |
+ * returned pointer if it was defaulting to the 'other' variant |
+ * because no explicit value was stored. |
+ */ |
+ T *getMutableWithDefault( |
+ Category category, |
+ const T &defaultValue, |
+ UErrorCode &status) { |
+ return getMutable(category, &defaultValue, status); |
+ } |
+ |
+ /** |
+ * Returns TRUE if this object equals rhs. |
+ */ |
+ UBool equals( |
+ const PluralMap<T> &rhs, |
+ UBool (*eqFunc)(const T &, const T &)) const { |
+ for (int32_t i = 0; i < UPRV_LENGTHOF(fVariants); ++i) { |
+ if (fVariants[i] == rhs.fVariants[i]) { |
+ continue; |
+ } |
+ if (fVariants[i] == NULL || rhs.fVariants[i] == NULL) { |
+ return FALSE; |
+ } |
+ if (!eqFunc(*fVariants[i], *rhs.fVariants[i])) { |
+ return FALSE; |
+ } |
+ } |
+ return TRUE; |
+ } |
+ |
+private: |
+ T fOtherVariant; |
+ T* fVariants[6]; |
+ |
+ T *getMutable( |
+ Category category, |
+ const T *defaultValue, |
+ UErrorCode &status) { |
+ if (U_FAILURE(status)) { |
+ return NULL; |
+ } |
+ int32_t index = category; |
+ if (index < 0 || index >= UPRV_LENGTHOF(fVariants)) { |
+ status = U_ILLEGAL_ARGUMENT_ERROR; |
+ return NULL; |
+ } |
+ if (fVariants[index] == NULL) { |
+ fVariants[index] = defaultValue == NULL ? |
+ new T() : new T(*defaultValue); |
+ } |
+ if (!fVariants[index]) { |
+ status = U_MEMORY_ALLOCATION_ERROR; |
+ } |
+ return fVariants[index]; |
+ } |
+ |
+ void initializeNew() { |
+ fVariants[0] = &fOtherVariant; |
+ for (int32_t i = 1; i < UPRV_LENGTHOF(fVariants); ++i) { |
+ fVariants[i] = NULL; |
+ } |
+ } |
+}; |
+ |
+U_NAMESPACE_END |
+ |
+#endif |