2020-08-11 09:10:23 +00:00
|
|
|
// © 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
|
2021-04-22 12:08:59 +00:00
|
|
|
* category, but rather represents the absence of a plural category.
|
2020-08-11 09:10:23 +00:00
|
|
|
*/
|
|
|
|
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
|