pluralmap.h 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  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. #ifndef __PLURAL_MAP_H__
  13. #define __PLURAL_MAP_H__
  14. #include "unicode/uobject.h"
  15. #include "cmemory.h"
  16. U_NAMESPACE_BEGIN
  17. class UnicodeString;
  18. class U_COMMON_API PluralMapBase : public UMemory {
  19. public:
  20. /**
  21. * The names of all the plural categories. NONE is not an actual plural
  22. * category, but rather represents the absense of a plural category.
  23. */
  24. enum Category {
  25. NONE = -1,
  26. OTHER,
  27. ZERO,
  28. ONE,
  29. TWO,
  30. FEW,
  31. MANY,
  32. CATEGORY_COUNT
  33. };
  34. /**
  35. * Converts a category name such as "zero", "one", "two", "few", "many"
  36. * or "other" to a category enum. Returns NONE for an unrecognized
  37. * category name.
  38. */
  39. static Category toCategory(const char *categoryName);
  40. /**
  41. * Converts a category name such as "zero", "one", "two", "few", "many"
  42. * or "other" to a category enum. Returns NONE for urecongized
  43. * category name.
  44. */
  45. static Category toCategory(const UnicodeString &categoryName);
  46. /**
  47. * Converts a category to a name.
  48. * Passing NONE or CATEGORY_COUNT for category returns NULL.
  49. */
  50. static const char *getCategoryName(Category category);
  51. };
  52. /**
  53. * A Map of plural categories to values. It maintains ownership of the
  54. * values.
  55. *
  56. * Type T is the value type. T must provide the followng:
  57. * 1) Default constructor
  58. * 2) Copy constructor
  59. * 3) Assignment operator
  60. * 4) Must extend UMemory
  61. */
  62. template<typename T>
  63. class PluralMap : public PluralMapBase {
  64. public:
  65. /**
  66. * Other category is maps to a copy of the default value.
  67. */
  68. PluralMap() : fOtherVariant() {
  69. initializeNew();
  70. }
  71. /**
  72. * Other category is mapped to otherVariant.
  73. */
  74. PluralMap(const T &otherVariant) : fOtherVariant(otherVariant) {
  75. initializeNew();
  76. }
  77. PluralMap(const PluralMap<T> &other) : fOtherVariant(other.fOtherVariant) {
  78. fVariants[0] = &fOtherVariant;
  79. for (int32_t i = 1; i < UPRV_LENGTHOF(fVariants); ++i) {
  80. fVariants[i] = other.fVariants[i] ?
  81. new T(*other.fVariants[i]) : NULL;
  82. }
  83. }
  84. PluralMap<T> &operator=(const PluralMap<T> &other) {
  85. if (this == &other) {
  86. return *this;
  87. }
  88. for (int32_t i = 0; i < UPRV_LENGTHOF(fVariants); ++i) {
  89. if (fVariants[i] != NULL && other.fVariants[i] != NULL) {
  90. *fVariants[i] = *other.fVariants[i];
  91. } else if (fVariants[i] != NULL) {
  92. delete fVariants[i];
  93. fVariants[i] = NULL;
  94. } else if (other.fVariants[i] != NULL) {
  95. fVariants[i] = new T(*other.fVariants[i]);
  96. } else {
  97. // do nothing
  98. }
  99. }
  100. return *this;
  101. }
  102. ~PluralMap() {
  103. for (int32_t i = 1; i < UPRV_LENGTHOF(fVariants); ++i) {
  104. delete fVariants[i];
  105. }
  106. }
  107. /**
  108. * Removes all mappings and makes 'other' point to the default value.
  109. */
  110. void clear() {
  111. *fVariants[0] = T();
  112. for (int32_t i = 1; i < UPRV_LENGTHOF(fVariants); ++i) {
  113. delete fVariants[i];
  114. fVariants[i] = NULL;
  115. }
  116. }
  117. /**
  118. * Iterates through the mappings in this instance, set index to NONE
  119. * prior to using. Call next repeatedly to get the values until it
  120. * returns NULL. Each time next returns, caller may pass index
  121. * to getCategoryName() to get the name of the plural category.
  122. * When this function returns NULL, index is CATEGORY_COUNT
  123. */
  124. const T *next(Category &index) const {
  125. int32_t idx = index;
  126. ++idx;
  127. for (; idx < UPRV_LENGTHOF(fVariants); ++idx) {
  128. if (fVariants[idx] != NULL) {
  129. index = static_cast<Category>(idx);
  130. return fVariants[idx];
  131. }
  132. }
  133. index = static_cast<Category>(idx);
  134. return NULL;
  135. }
  136. /**
  137. * non const version of next.
  138. */
  139. T *nextMutable(Category &index) {
  140. const T *result = next(index);
  141. return const_cast<T *>(result);
  142. }
  143. /**
  144. * Returns the 'other' variant.
  145. * Same as calling get(OTHER).
  146. */
  147. const T &getOther() const {
  148. return get(OTHER);
  149. }
  150. /**
  151. * Returns the value associated with a category.
  152. * If no value found, or v is NONE or CATEGORY_COUNT, falls
  153. * back to returning the value for the 'other' category.
  154. */
  155. const T &get(Category v) const {
  156. int32_t index = v;
  157. if (index < 0 || index >= UPRV_LENGTHOF(fVariants) || fVariants[index] == NULL) {
  158. return *fVariants[0];
  159. }
  160. return *fVariants[index];
  161. }
  162. /**
  163. * Convenience routine to get the value by category name. Otherwise
  164. * works just like get(Category).
  165. */
  166. const T &get(const char *category) const {
  167. return get(toCategory(category));
  168. }
  169. /**
  170. * Convenience routine to get the value by category name as a
  171. * UnicodeString. Otherwise works just like get(category).
  172. */
  173. const T &get(const UnicodeString &category) const {
  174. return get(toCategory(category));
  175. }
  176. /**
  177. * Returns a pointer to the value associated with a category
  178. * that caller can safely modify. If the value was defaulting to the 'other'
  179. * variant because no explicit value was stored, this method creates a
  180. * new value using the default constructor at the returned pointer.
  181. *
  182. * @param category the category with the value to change.
  183. * @param status error returned here if index is NONE or CATEGORY_COUNT
  184. * or memory could not be allocated, or any other error happens.
  185. */
  186. T *getMutable(
  187. Category category,
  188. UErrorCode &status) {
  189. return getMutable(category, NULL, status);
  190. }
  191. /**
  192. * Convenience routine to get a mutable pointer to a value by category name.
  193. * Otherwise works just like getMutable(Category, UErrorCode &).
  194. * reports an error if the category name is invalid.
  195. */
  196. T *getMutable(
  197. const char *category,
  198. UErrorCode &status) {
  199. return getMutable(toCategory(category), NULL, status);
  200. }
  201. /**
  202. * Just like getMutable(Category, UErrorCode &) but copies defaultValue to
  203. * returned pointer if it was defaulting to the 'other' variant
  204. * because no explicit value was stored.
  205. */
  206. T *getMutableWithDefault(
  207. Category category,
  208. const T &defaultValue,
  209. UErrorCode &status) {
  210. return getMutable(category, &defaultValue, status);
  211. }
  212. /**
  213. * Returns TRUE if this object equals rhs.
  214. */
  215. UBool equals(
  216. const PluralMap<T> &rhs,
  217. UBool (*eqFunc)(const T &, const T &)) const {
  218. for (int32_t i = 0; i < UPRV_LENGTHOF(fVariants); ++i) {
  219. if (fVariants[i] == rhs.fVariants[i]) {
  220. continue;
  221. }
  222. if (fVariants[i] == NULL || rhs.fVariants[i] == NULL) {
  223. return FALSE;
  224. }
  225. if (!eqFunc(*fVariants[i], *rhs.fVariants[i])) {
  226. return FALSE;
  227. }
  228. }
  229. return TRUE;
  230. }
  231. private:
  232. T fOtherVariant;
  233. T* fVariants[6];
  234. T *getMutable(
  235. Category category,
  236. const T *defaultValue,
  237. UErrorCode &status) {
  238. if (U_FAILURE(status)) {
  239. return NULL;
  240. }
  241. int32_t index = category;
  242. if (index < 0 || index >= UPRV_LENGTHOF(fVariants)) {
  243. status = U_ILLEGAL_ARGUMENT_ERROR;
  244. return NULL;
  245. }
  246. if (fVariants[index] == NULL) {
  247. fVariants[index] = defaultValue == NULL ?
  248. new T() : new T(*defaultValue);
  249. }
  250. if (!fVariants[index]) {
  251. status = U_MEMORY_ALLOCATION_ERROR;
  252. }
  253. return fVariants[index];
  254. }
  255. void initializeNew() {
  256. fVariants[0] = &fOtherVariant;
  257. for (int32_t i = 1; i < UPRV_LENGTHOF(fVariants); ++i) {
  258. fVariants[i] = NULL;
  259. }
  260. }
  261. };
  262. U_NAMESPACE_END
  263. #endif