// © 2016 and later: Unicode, Inc. and others. // License & terms of use: http://www.unicode.org/copyright.html /* ****************************************************************************** * 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