w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

plurrule.cpp
Go to the documentation of this file.
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 *******************************************************************************
5 * Copyright (C) 2007-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 *******************************************************************************
8 *
9 * File plurrule.cpp
10 */
11 
12 #include <math.h>
13 #include <stdio.h>
14 
15 #include "unicode/utypes.h"
16 #include "unicode/localpointer.h"
17 #include "unicode/plurrule.h"
18 #include "unicode/upluralrules.h"
19 #include "unicode/ures.h"
20 #include "unicode/numfmt.h"
21 #include "unicode/decimfmt.h"
23 #include "charstr.h"
24 #include "cmemory.h"
25 #include "cstring.h"
26 #include "hash.h"
27 #include "locutil.h"
28 #include "mutex.h"
29 #include "patternprops.h"
30 #include "plurrule_impl.h"
31 #include "putilimp.h"
32 #include "ucln_in.h"
33 #include "ustrfmt.h"
34 #include "uassert.h"
35 #include "uvectr32.h"
36 #include "sharedpluralrules.h"
37 #include "unifiedcache.h"
38 #include "number_decimalquantity.h"
39 #include "util.h"
40 #include "pluralranges.h"
41 #include "numrange_impl.h"
42 
43 #if !UCONFIG_NO_FORMATTING
44 
46 
47 using namespace icu::pluralimpl;
48 using icu::number::impl::DecimalQuantity;
49 
52 static const UChar PK_IN[]={LOW_I,LOW_N,0};
53 static const UChar PK_NOT[]={LOW_N,LOW_O,LOW_T,0};
54 static const UChar PK_IS[]={LOW_I,LOW_S,0};
55 static const UChar PK_MOD[]={LOW_M,LOW_O,LOW_D,0};
56 static const UChar PK_AND[]={LOW_A,LOW_N,LOW_D,0};
57 static const UChar PK_OR[]={LOW_O,LOW_R,0};
58 static const UChar PK_VAR_N[]={LOW_N,0};
59 static const UChar PK_VAR_I[]={LOW_I,0};
60 static const UChar PK_VAR_F[]={LOW_F,0};
61 static const UChar PK_VAR_T[]={LOW_T,0};
62 static const UChar PK_VAR_E[]={LOW_E,0};
63 static const UChar PK_VAR_V[]={LOW_V,0};
67 
70 
71 PluralRules::PluralRules(UErrorCode& /*status*/)
72 : UObject(),
73  mRules(nullptr),
74  mStandardPluralRanges(nullptr),
75  mInternalStatus(U_ZERO_ERROR)
76 {
77 }
78 
79 PluralRules::PluralRules(const PluralRules& other)
80 : UObject(other),
81  mRules(nullptr),
82  mStandardPluralRanges(nullptr),
83  mInternalStatus(U_ZERO_ERROR)
84 {
85  *this=other;
86 }
87 
88 PluralRules::~PluralRules() {
89  delete mRules;
90  delete mStandardPluralRanges;
91 }
92 
94  delete ptr;
95 }
96 
97 PluralRules*
98 PluralRules::clone() const {
99  // Since clone doesn't have a 'status' parameter, the best we can do is return nullptr if
100  // the newly created object was not fully constructed properly (an error occurred).
101  UErrorCode localStatus = U_ZERO_ERROR;
102  return clone(localStatus);
103 }
104 
105 PluralRules*
106 PluralRules::clone(UErrorCode& status) const {
107  LocalPointer<PluralRules> newObj(new PluralRules(*this), status);
108  if (U_SUCCESS(status) && U_FAILURE(newObj->mInternalStatus)) {
109  status = newObj->mInternalStatus;
110  newObj.adoptInstead(nullptr);
111  }
112  return newObj.orphan();
113 }
114 
115 PluralRules&
116 PluralRules::operator=(const PluralRules& other) {
117  if (this != &other) {
118  delete mRules;
119  mRules = nullptr;
120  delete mStandardPluralRanges;
121  mStandardPluralRanges = nullptr;
122  mInternalStatus = other.mInternalStatus;
123  if (U_FAILURE(mInternalStatus)) {
124  // bail out early if the object we were copying from was already 'invalid'.
125  return *this;
126  }
127  if (other.mRules != nullptr) {
128  mRules = new RuleChain(*other.mRules);
129  if (mRules == nullptr) {
130  mInternalStatus = U_MEMORY_ALLOCATION_ERROR;
131  }
132  else if (U_FAILURE(mRules->fInternalStatus)) {
133  // If the RuleChain wasn't fully copied, then set our status to failure as well.
134  mInternalStatus = mRules->fInternalStatus;
135  }
136  }
137  if (other.mStandardPluralRanges != nullptr) {
138  mStandardPluralRanges = other.mStandardPluralRanges->copy(mInternalStatus)
139  .toPointer(mInternalStatus)
140  .orphan();
141  }
142  }
143  return *this;
144 }
145 
146 StringEnumeration* PluralRules::getAvailableLocales(UErrorCode &status) {
147  if (U_FAILURE(status)) {
148  return nullptr;
149  }
150  LocalPointer<StringEnumeration> result(new PluralAvailableLocalesEnumeration(status), status);
151  if (U_FAILURE(status)) {
152  return nullptr;
153  }
154  return result.orphan();
155 }
156 
157 
158 PluralRules* U_EXPORT2
159 PluralRules::createRules(const UnicodeString& description, UErrorCode& status) {
160  if (U_FAILURE(status)) {
161  return nullptr;
162  }
164  LocalPointer<PluralRules> newRules(new PluralRules(status), status);
165  if (U_FAILURE(status)) {
166  return nullptr;
167  }
168  parser.parse(description, newRules.getAlias(), status);
169  if (U_FAILURE(status)) {
170  newRules.adoptInstead(nullptr);
171  }
172  return newRules.orphan();
173 }
174 
175 
176 PluralRules* U_EXPORT2
177 PluralRules::createDefaultRules(UErrorCode& status) {
178  return createRules(UnicodeString(TRUE, PLURAL_DEFAULT_RULE, -1), status);
179 }
180 
181 /******************************************************************************/
182 /* Create PluralRules cache */
183 
184 template<> U_I18N_API
186  const void * /*unused*/, UErrorCode &status) const {
187  const char *localeId = fLoc.getName();
188  LocalPointer<PluralRules> pr(PluralRules::internalForLocale(localeId, UPLURAL_TYPE_CARDINAL, status), status);
189  if (U_FAILURE(status)) {
190  return nullptr;
191  }
192  LocalPointer<SharedPluralRules> result(new SharedPluralRules(pr.getAlias()), status);
193  if (U_FAILURE(status)) {
194  return nullptr;
195  }
196  pr.orphan(); // result was successfully created so it nows pr.
197  result->addRef();
198  return result.orphan();
199 }
200 
201 /* end plural rules cache */
202 /******************************************************************************/
203 
205 PluralRules::createSharedInstance(
206  const Locale& locale, UPluralType type, UErrorCode& status) {
207  if (U_FAILURE(status)) {
208  return nullptr;
209  }
210  if (type != UPLURAL_TYPE_CARDINAL) {
212  return nullptr;
213  }
214  const SharedPluralRules *result = nullptr;
216  return result;
217 }
218 
219 PluralRules* U_EXPORT2
220 PluralRules::forLocale(const Locale& locale, UErrorCode& status) {
221  return forLocale(locale, UPLURAL_TYPE_CARDINAL, status);
222 }
223 
224 PluralRules* U_EXPORT2
225 PluralRules::forLocale(const Locale& locale, UPluralType type, UErrorCode& status) {
226  if (type != UPLURAL_TYPE_CARDINAL) {
227  return internalForLocale(locale, type, status);
228  }
229  const SharedPluralRules *shared = createSharedInstance(
230  locale, type, status);
231  if (U_FAILURE(status)) {
232  return nullptr;
233  }
234  PluralRules *result = (*shared)->clone(status);
235  shared->removeRef();
236  return result;
237 }
238 
239 PluralRules* U_EXPORT2
240 PluralRules::internalForLocale(const Locale& locale, UPluralType type, UErrorCode& status) {
241  if (U_FAILURE(status)) {
242  return nullptr;
243  }
244  if (type >= UPLURAL_TYPE_COUNT) {
246  return nullptr;
247  }
248  LocalPointer<PluralRules> newObj(new PluralRules(status), status);
249  if (U_FAILURE(status)) {
250  return nullptr;
251  }
252  UnicodeString locRule = newObj->getRuleFromResource(locale, type, status);
253  // TODO: which other errors, if any, should be returned?
254  if (locRule.length() == 0) {
255  // If an out-of-memory error occurred, then stop and report the failure.
257  return nullptr;
258  }
259  // Locales with no specific rules (all numbers have the "other" category
260  // will return a U_MISSING_RESOURCE_ERROR at this point. This is not
261  // an error.
262  locRule = UnicodeString(PLURAL_DEFAULT_RULE);
264  }
266  parser.parse(locRule, newObj.getAlias(), status);
267  // TODO: should rule parse errors be returned, or
268  // should we silently use default rules?
269  // Original impl used default rules.
270  // Ask the question to ICU Core.
271 
272  newObj->mStandardPluralRanges = StandardPluralRanges::forLocale(locale, status)
273  .toPointer(status)
274  .orphan();
275 
276  return newObj.orphan();
277 }
278 
279 UnicodeString
281  return select(FixedDecimal(number));
282 }
283 
284 UnicodeString
285 PluralRules::select(double number) const {
286  return select(FixedDecimal(number));
287 }
288 
289 UnicodeString
290 PluralRules::select(const number::FormattedNumber& number, UErrorCode& status) const {
291  DecimalQuantity dq;
292  number.getDecimalQuantity(dq, status);
293  if (U_FAILURE(status)) {
295  }
296  if (U_FAILURE(mInternalStatus)) {
297  status = mInternalStatus;
299  }
300  return select(dq);
301 }
302 
303 UnicodeString
305  if (mRules == nullptr) {
306  return UnicodeString(TRUE, PLURAL_DEFAULT_RULE, -1);
307  }
308  else {
309  return mRules->select(number);
310  }
311 }
312 
313 UnicodeString
314 PluralRules::select(const number::FormattedNumberRange& range, UErrorCode& status) const {
315  return select(range.getData(status), status);
316 }
317 
318 UnicodeString
320  if (U_FAILURE(status)) {
322  }
323  if (U_FAILURE(mInternalStatus)) {
324  status = mInternalStatus;
326  }
327  if (mStandardPluralRanges == nullptr) {
328  // Happens if PluralRules was constructed via createRules()
331  }
332  auto form1 = StandardPlural::fromString(select(impl->quantity1), status);
333  auto form2 = StandardPlural::fromString(select(impl->quantity2), status);
334  if (U_FAILURE(status)) {
336  }
337  auto result = mStandardPluralRanges->resolve(form1, form2);
338  return UnicodeString(StandardPlural::getKeyword(result), -1, US_INV);
339 }
340 
341 
342 StringEnumeration*
343 PluralRules::getKeywords(UErrorCode& status) const {
344  if (U_FAILURE(status)) {
345  return nullptr;
346  }
347  if (U_FAILURE(mInternalStatus)) {
348  status = mInternalStatus;
349  return nullptr;
350  }
351  LocalPointer<StringEnumeration> nameEnumerator(new PluralKeywordEnumeration(mRules, status), status);
352  if (U_FAILURE(status)) {
353  return nullptr;
354  }
355  return nameEnumerator.orphan();
356 }
357 
358 double
359 PluralRules::getUniqueKeywordValue(const UnicodeString& /* keyword */) {
360  // Not Implemented.
361  return UPLRULES_NO_UNIQUE_VALUE;
362 }
363 
364 int32_t
365 PluralRules::getAllKeywordValues(const UnicodeString & /* keyword */, double * /* dest */,
366  int32_t /* destCapacity */, UErrorCode& error) {
368  return 0;
369 }
370 
371 
372 static double scaleForInt(double d) {
373  double scale = 1.0;
374  while (d != floor(d)) {
375  d = d * 10.0;
376  scale = scale * 10.0;
377  }
378  return scale;
379 }
380 
381 /**
382  * Helper method for the overrides of getSamples() for double and FixedDecimal
383  * return value types. Provide only one of an allocated array of doubles or
384  * FixedDecimals, and a nullptr for the other.
385  */
386 static int32_t
387 getSamplesFromString(const UnicodeString &samples, double *destDbl,
388  FixedDecimal* destFd, int32_t destCapacity,
389  UErrorCode& status) {
390 
391  if ((destDbl == nullptr && destFd == nullptr)
392  || (destDbl != nullptr && destFd != nullptr)) {
394  return 0;
395  }
396 
397  bool isDouble = destDbl != nullptr;
398  int32_t sampleCount = 0;
399  int32_t sampleStartIdx = 0;
400  int32_t sampleEndIdx = 0;
401 
402  //std::string ss; // TODO: debugging.
403  // std::cout << "PluralRules::getSamples(), samples = \"" << samples.toUTF8String(ss) << "\"\n";
404  for (sampleCount = 0; sampleCount < destCapacity && sampleStartIdx < samples.length(); ) {
405  sampleEndIdx = samples.indexOf(COMMA, sampleStartIdx);
406  if (sampleEndIdx == -1) {
407  sampleEndIdx = samples.length();
408  }
409  const UnicodeString &sampleRange = samples.tempSubStringBetween(sampleStartIdx, sampleEndIdx);
410  // ss.erase();
411  // std::cout << "PluralRules::getSamples(), samplesRange = \"" << sampleRange.toUTF8String(ss) << "\"\n";
412  int32_t tildeIndex = sampleRange.indexOf(TILDE);
413  if (tildeIndex < 0) {
414  FixedDecimal fixed(sampleRange, status);
415  if (isDouble) {
416  double sampleValue = fixed.source;
417  if (fixed.visibleDecimalDigitCount == 0 || sampleValue != floor(sampleValue)) {
418  destDbl[sampleCount++] = sampleValue;
419  }
420  } else {
421  destFd[sampleCount++] = fixed;
422  }
423  } else {
424 
425  FixedDecimal fixedLo(sampleRange.tempSubStringBetween(0, tildeIndex), status);
426  FixedDecimal fixedHi(sampleRange.tempSubStringBetween(tildeIndex+1), status);
427  double rangeLo = fixedLo.source;
428  double rangeHi = fixedHi.source;
429  if (U_FAILURE(status)) {
430  break;
431  }
432  if (rangeHi < rangeLo) {
434  break;
435  }
436 
437  // For ranges of samples with fraction decimal digits, scale the number up so that we
438  // are adding one in the units place. Avoids roundoffs from repetitive adds of tenths.
439 
440  double scale = scaleForInt(rangeLo);
441  double t = scaleForInt(rangeHi);
442  if (t > scale) {
443  scale = t;
444  }
445  rangeLo *= scale;
446  rangeHi *= scale;
447  for (double n=rangeLo; n<=rangeHi; n+=1) {
448  double sampleValue = n/scale;
449  if (isDouble) {
450  // Hack Alert: don't return any decimal samples with integer values that
451  // originated from a format with trailing decimals.
452  // This API is returning doubles, which can't distinguish having displayed
453  // zeros to the right of the decimal.
454  // This results in test failures with values mapping back to a different keyword.
455  if (!(sampleValue == floor(sampleValue) && fixedLo.visibleDecimalDigitCount > 0)) {
456  destDbl[sampleCount++] = sampleValue;
457  }
458  } else {
462  destFd[sampleCount++] = newSample;
463  }
464  if (sampleCount >= destCapacity) {
465  break;
466  }
467  }
468  }
469  sampleStartIdx = sampleEndIdx + 1;
470  }
471  return sampleCount;
472 }
473 
474 int32_t
475 PluralRules::getSamples(const UnicodeString &keyword, double *dest,
476  int32_t destCapacity, UErrorCode& status) {
477  if (U_FAILURE(status)) {
478  return 0;
479  }
480  if (U_FAILURE(mInternalStatus)) {
481  status = mInternalStatus;
482  return 0;
483  }
484  if (dest != nullptr ? destCapacity < 0 : destCapacity != 0) {
486  return 0;
487  }
488  RuleChain *rc = rulesForKeyword(keyword);
489  if (rc == nullptr) {
490  return 0;
491  }
492  int32_t numSamples = getSamplesFromString(rc->fIntegerSamples, dest, nullptr, destCapacity, status);
493  if (numSamples == 0) {
494  numSamples = getSamplesFromString(rc->fDecimalSamples, dest, nullptr, destCapacity, status);
495  }
496  return numSamples;
497 }
498 
499 int32_t
500 PluralRules::getSamples(const UnicodeString &keyword, FixedDecimal *dest,
501  int32_t destCapacity, UErrorCode& status) {
502  if (U_FAILURE(status)) {
503  return 0;
504  }
505  if (U_FAILURE(mInternalStatus)) {
506  status = mInternalStatus;
507  return 0;
508  }
509  if (dest != nullptr ? destCapacity < 0 : destCapacity != 0) {
511  return 0;
512  }
513  RuleChain *rc = rulesForKeyword(keyword);
514  if (rc == nullptr) {
515  return 0;
516  }
517  int32_t numSamples = getSamplesFromString(rc->fIntegerSamples, nullptr, dest, destCapacity, status);
518  if (numSamples == 0) {
519  numSamples = getSamplesFromString(rc->fDecimalSamples, nullptr, dest, destCapacity, status);
520  }
521  return numSamples;
522 }
523 
524 
525 RuleChain *PluralRules::rulesForKeyword(const UnicodeString &keyword) const {
526  RuleChain *rc;
527  for (rc = mRules; rc != nullptr; rc = rc->fNext) {
528  if (rc->fKeyword == keyword) {
529  break;
530  }
531  }
532  return rc;
533 }
534 
535 
536 UBool
537 PluralRules::isKeyword(const UnicodeString& keyword) const {
538  if (0 == keyword.compare(PLURAL_KEYWORD_OTHER, 5)) {
539  return true;
540  }
541  return rulesForKeyword(keyword) != nullptr;
542 }
543 
544 UnicodeString
545 PluralRules::getKeywordOther() const {
546  return UnicodeString(TRUE, PLURAL_KEYWORD_OTHER, 5);
547 }
548 
549 UBool
550 PluralRules::operator==(const PluralRules& other) const {
551  const UnicodeString *ptrKeyword;
553 
554  if ( this == &other ) {
555  return TRUE;
556  }
557  LocalPointer<StringEnumeration> myKeywordList(getKeywords(status));
558  LocalPointer<StringEnumeration> otherKeywordList(other.getKeywords(status));
559  if (U_FAILURE(status)) {
560  return FALSE;
561  }
562 
563  if (myKeywordList->count(status)!=otherKeywordList->count(status)) {
564  return FALSE;
565  }
566  myKeywordList->reset(status);
567  while ((ptrKeyword=myKeywordList->snext(status))!=nullptr) {
568  if (!other.isKeyword(*ptrKeyword)) {
569  return FALSE;
570  }
571  }
572  otherKeywordList->reset(status);
573  while ((ptrKeyword=otherKeywordList->snext(status))!=nullptr) {
574  if (!this->isKeyword(*ptrKeyword)) {
575  return FALSE;
576  }
577  }
578  if (U_FAILURE(status)) {
579  return FALSE;
580  }
581 
582  return TRUE;
583 }
584 
585 
586 void
587 PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErrorCode &status)
588 {
589  if (U_FAILURE(status)) {
590  return;
591  }
592  U_ASSERT(ruleIndex == 0); // Parsers are good for a single use only!
593  ruleSrc = &ruleData;
594 
595  while (ruleIndex< ruleSrc->length()) {
597  if (U_FAILURE(status)) {
598  return;
599  }
601  if (U_FAILURE(status)) {
602  return;
603  }
604  switch (type) {
605  case tAnd:
606  U_ASSERT(curAndConstraint != nullptr);
608  break;
609  case tOr:
610  {
611  U_ASSERT(currentChain != nullptr);
613  while (orNode->next != nullptr) {
614  orNode = orNode->next;
615  }
616  orNode->next= new OrConstraint();
617  if (orNode->next == nullptr) {
619  break;
620  }
621  orNode=orNode->next;
622  orNode->next=nullptr;
623  curAndConstraint = orNode->add(status);
624  }
625  break;
626  case tIs:
627  U_ASSERT(curAndConstraint != nullptr);
629  U_ASSERT(curAndConstraint->rangeList == nullptr);
630  break;
631  case tNot:
632  U_ASSERT(curAndConstraint != nullptr);
634  break;
635 
636  case tNotEqual:
639  case tIn:
640  case tWithin:
641  case tEqual:
642  {
643  U_ASSERT(curAndConstraint != nullptr);
644  LocalPointer<UVector32> newRangeList(new UVector32(status), status);
645  if (U_FAILURE(status)) {
646  break;
647  }
648  curAndConstraint->rangeList = newRangeList.orphan();
649  curAndConstraint->rangeList->addElement(-1, status); // range Low
650  curAndConstraint->rangeList->addElement(-1, status); // range Hi
651  rangeLowIdx = 0;
652  rangeHiIdx = 1;
655  }
656  break;
657  case tNumber:
658  U_ASSERT(curAndConstraint != nullptr);
660  (curAndConstraint->opNum == -1 ) ) {
662  }
663  else {
664  if (curAndConstraint->rangeList == nullptr) {
665  // this is for an 'is' rule
667  } else {
668  // this is for an 'in' or 'within' rule
672  }
673  else {
677  // Range Lower bound > Range Upper bound.
678  // U_UNEXPECTED_TOKEN seems a little funny, but it is consistently
679  // used for all plural rule parse errors.
681  break;
682  }
683  }
684  }
685  }
686  break;
687  case tComma:
688  // TODO: rule syntax checking is inadequate, can happen with badly formed rules.
689  // Catch cases like "n mod 10, is 1" here instead.
690  if (curAndConstraint == nullptr || curAndConstraint->rangeList == nullptr) {
692  break;
693  }
696  curAndConstraint->rangeList->addElement(-1, status); // range Low
698  curAndConstraint->rangeList->addElement(-1, status); // range Hi
699  break;
700  case tMod:
701  U_ASSERT(curAndConstraint != nullptr);
703  break;
704  case tVariableN:
705  case tVariableI:
706  case tVariableF:
707  case tVariableT:
708  case tVariableE:
709  case tVariableV:
710  U_ASSERT(curAndConstraint != nullptr);
712  break;
713  case tKeyword:
714  {
715  RuleChain *newChain = new RuleChain;
716  if (newChain == nullptr) {
718  break;
719  }
720  newChain->fKeyword = token;
721  if (prules->mRules == nullptr) {
722  prules->mRules = newChain;
723  } else {
724  // The new rule chain goes at the end of the linked list of rule chains,
725  // unless there is an "other" keyword & chain. "other" must remain last.
726  RuleChain *insertAfter = prules->mRules;
727  while (insertAfter->fNext!=nullptr &&
728  insertAfter->fNext->fKeyword.compare(PLURAL_KEYWORD_OTHER, 5) != 0 ){
729  insertAfter=insertAfter->fNext;
730  }
731  newChain->fNext = insertAfter->fNext;
732  insertAfter->fNext = newChain;
733  }
734  OrConstraint *orNode = new OrConstraint();
735  if (orNode == nullptr) {
737  break;
738  }
739  newChain->ruleHeader = orNode;
740  curAndConstraint = orNode->add(status);
741  currentChain = newChain;
742  }
743  break;
744 
745  case tInteger:
746  for (;;) {
748  if (U_FAILURE(status) || type == tSemiColon || type == tEOF || type == tAt) {
749  break;
750  }
751  if (type == tEllipsis) {
753  continue;
754  }
756  }
757  break;
758 
759  case tDecimal:
760  for (;;) {
762  if (U_FAILURE(status) || type == tSemiColon || type == tEOF || type == tAt) {
763  break;
764  }
765  if (type == tEllipsis) {
767  continue;
768  }
770  }
771  break;
772 
773  default:
774  break;
775  }
776  prevType=type;
777  if (U_FAILURE(status)) {
778  break;
779  }
780  }
781 }
782 
783 UnicodeString
784 PluralRules::getRuleFromResource(const Locale& locale, UPluralType type, UErrorCode& errCode) {
785  UnicodeString emptyStr;
786 
787  if (U_FAILURE(errCode)) {
788  return emptyStr;
789  }
790  LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "plurals", &errCode));
791  if(U_FAILURE(errCode)) {
792  return emptyStr;
793  }
794  const char *typeKey;
795  switch (type) {
797  typeKey = "locales";
798  break;
800  typeKey = "locales_ordinals";
801  break;
802  default:
803  // Must not occur: The caller should have checked for valid types.
805  return emptyStr;
806  }
807  LocalUResourceBundlePointer locRes(ures_getByKey(rb.getAlias(), typeKey, nullptr, &errCode));
808  if(U_FAILURE(errCode)) {
809  return emptyStr;
810  }
811  int32_t resLen=0;
812  const char *curLocaleName=locale.getBaseName();
813  const UChar* s = ures_getStringByKey(locRes.getAlias(), curLocaleName, &resLen, &errCode);
814 
815  if (s == nullptr) {
816  // Check parent locales.
818  char parentLocaleName[ULOC_FULLNAME_CAPACITY];
819  const char *curLocaleName2=locale.getBaseName();
820  uprv_strcpy(parentLocaleName, curLocaleName2);
821 
822  while (uloc_getParent(parentLocaleName, parentLocaleName,
824  resLen=0;
825  s = ures_getStringByKey(locRes.getAlias(), parentLocaleName, &resLen, &status);
826  if (s != nullptr) {
828  break;
829  }
831  }
832  }
833  if (s==nullptr) {
834  return emptyStr;
835  }
836 
837  char setKey[256];
838  u_UCharsToChars(s, setKey, resLen + 1);
839  // printf("\n PluralRule: %s\n", setKey);
840 
841  LocalUResourceBundlePointer ruleRes(ures_getByKey(rb.getAlias(), "rules", nullptr, &errCode));
842  if(U_FAILURE(errCode)) {
843  return emptyStr;
844  }
845  LocalUResourceBundlePointer setRes(ures_getByKey(ruleRes.getAlias(), setKey, nullptr, &errCode));
846  if (U_FAILURE(errCode)) {
847  return emptyStr;
848  }
849 
850  int32_t numberKeys = ures_getSize(setRes.getAlias());
851  UnicodeString result;
852  const char *key=nullptr;
853  for(int32_t i=0; i<numberKeys; ++i) { // Keys are zero, one, few, ...
854  UnicodeString rules = ures_getNextUnicodeString(setRes.getAlias(), &key, &errCode);
855  UnicodeString uKey(key, -1, US_INV);
856  result.append(uKey);
857  result.append(COLON);
858  result.append(rules);
859  result.append(SEMI_COLON);
860  }
861  return result;
862 }
863 
864 
865 UnicodeString
866 PluralRules::getRules() const {
867  UnicodeString rules;
868  if (mRules != nullptr) {
869  mRules->dumpRules(rules);
870  }
871  return rules;
872 }
873 
875  this->fInternalStatus = other.fInternalStatus;
876  if (U_FAILURE(fInternalStatus)) {
877  return; // stop early if the object we are copying from is invalid.
878  }
879  this->op = other.op;
880  this->opNum=other.opNum;
881  this->value=other.value;
882  if (other.rangeList != nullptr) {
883  LocalPointer<UVector32> newRangeList(new UVector32(fInternalStatus), fInternalStatus);
884  if (U_FAILURE(fInternalStatus)) {
885  return;
886  }
887  this->rangeList = newRangeList.orphan();
888  this->rangeList->assign(*other.rangeList, fInternalStatus);
889  }
890  this->integerOnly=other.integerOnly;
891  this->negated=other.negated;
892  this->digitsType = other.digitsType;
893  if (other.next != nullptr) {
894  this->next = new AndConstraint(*other.next);
895  if (this->next == nullptr) {
897  }
898  }
899 }
900 
902  delete rangeList;
903  rangeList = nullptr;
904  delete next;
905  next = nullptr;
906 }
907 
908 UBool
910  UBool result = TRUE;
911  if (digitsType == none) {
912  // An empty AndConstraint, created by a rule with a keyword but no following expression.
913  return TRUE;
914  }
915 
917  double n = number.getPluralOperand(operand); // pulls n | i | v | f value for the number.
918  // Will always be positive.
919  // May be non-integer (n option only)
920  do {
921  if (integerOnly && n != uprv_floor(n)) {
922  result = FALSE;
923  break;
924  }
925 
926  if (op == MOD) {
927  n = fmod(n, opNum);
928  }
929  if (rangeList == nullptr) {
930  result = value == -1 || // empty rule
931  n == value; // 'is' rule
932  break;
933  }
934  result = FALSE; // 'in' or 'within' rule
935  for (int32_t r=0; r<rangeList->size(); r+=2) {
936  if (rangeList->elementAti(r) <= n && n <= rangeList->elementAti(r+1)) {
937  result = TRUE;
938  break;
939  }
940  }
941  } while (FALSE);
942 
943  if (negated) {
944  result = !result;
945  }
946  return result;
947 }
948 
951  if (U_FAILURE(fInternalStatus)) {
953  return nullptr;
954  }
955  this->next = new AndConstraint();
956  if (this->next == nullptr) {
957  status = U_MEMORY_ALLOCATION_ERROR;
958  }
959  return this->next;
960 }
961 
962 
964  this->fInternalStatus = other.fInternalStatus;
965  if (U_FAILURE(fInternalStatus)) {
966  return; // stop early if the object we are copying from is invalid.
967  }
968  if ( other.childNode != nullptr ) {
969  this->childNode = new AndConstraint(*(other.childNode));
970  if (this->childNode == nullptr) {
972  return;
973  }
974  }
975  if (other.next != nullptr ) {
976  this->next = new OrConstraint(*(other.next));
977  if (this->next == nullptr) {
979  return;
980  }
981  if (U_FAILURE(this->next->fInternalStatus)) {
982  this->fInternalStatus = this->next->fInternalStatus;
983  }
984  }
985 }
986 
988  delete childNode;
989  childNode = nullptr;
990  delete next;
991  next = nullptr;
992 }
993 
996  if (U_FAILURE(fInternalStatus)) {
998  return nullptr;
999  }
1000  OrConstraint *curOrConstraint=this;
1001  {
1002  while (curOrConstraint->next!=nullptr) {
1003  curOrConstraint = curOrConstraint->next;
1004  }
1005  U_ASSERT(curOrConstraint->childNode == nullptr);
1006  curOrConstraint->childNode = new AndConstraint();
1007  if (curOrConstraint->childNode == nullptr) {
1009  }
1010  }
1011  return curOrConstraint->childNode;
1012 }
1013 
1014 UBool
1016  OrConstraint* orRule=this;
1017  UBool result=FALSE;
1018 
1019  while (orRule!=nullptr && !result) {
1020  result=TRUE;
1021  AndConstraint* andRule = orRule->childNode;
1022  while (andRule!=nullptr && result) {
1023  result = andRule->isFulfilled(number);
1024  andRule=andRule->next;
1025  }
1026  orRule = orRule->next;
1027  }
1028 
1029  return result;
1030 }
1031 
1032 
1034  fKeyword(other.fKeyword), fDecimalSamples(other.fDecimalSamples),
1035  fIntegerSamples(other.fIntegerSamples), fDecimalSamplesUnbounded(other.fDecimalSamplesUnbounded),
1036  fIntegerSamplesUnbounded(other.fIntegerSamplesUnbounded), fInternalStatus(other.fInternalStatus) {
1037  if (U_FAILURE(this->fInternalStatus)) {
1038  return; // stop early if the object we are copying from is invalid.
1039  }
1040  if (other.ruleHeader != nullptr) {
1041  this->ruleHeader = new OrConstraint(*(other.ruleHeader));
1042  if (this->ruleHeader == nullptr) {
1044  }
1045  else if (U_FAILURE(this->ruleHeader->fInternalStatus)) {
1046  // If the OrConstraint wasn't fully copied, then set our status to failure as well.
1048  return; // exit early.
1049  }
1050  }
1051  if (other.fNext != nullptr ) {
1052  this->fNext = new RuleChain(*other.fNext);
1053  if (this->fNext == nullptr) {
1055  }
1056  else if (U_FAILURE(this->fNext->fInternalStatus)) {
1057  // If the RuleChain wasn't fully copied, then set our status to failure as well.
1058  this->fInternalStatus = this->fNext->fInternalStatus;
1059  }
1060  }
1061 }
1062 
1064  delete fNext;
1065  delete ruleHeader;
1066 }
1067 
1068 UnicodeString
1070  if (!number.isNaN() && !number.isInfinite()) {
1071  for (const RuleChain *rules = this; rules != nullptr; rules = rules->fNext) {
1072  if (rules->ruleHeader->isFulfilled(number)) {
1073  return rules->fKeyword;
1074  }
1075  }
1076  }
1077  return UnicodeString(TRUE, PLURAL_KEYWORD_OTHER, 5);
1078 }
1079 
1080 static UnicodeString tokenString(tokenType tok) {
1081  UnicodeString s;
1082  switch (tok) {
1083  case tVariableN:
1084  s.append(LOW_N); break;
1085  case tVariableI:
1086  s.append(LOW_I); break;
1087  case tVariableF:
1088  s.append(LOW_F); break;
1089  case tVariableV:
1090  s.append(LOW_V); break;
1091  case tVariableT:
1092  s.append(LOW_T); break;
1093  case tVariableE:
1094  s.append(LOW_E); break;
1095  default:
1096  s.append(TILDE);
1097  }
1098  return s;
1099 }
1100 
1101 void
1102 RuleChain::dumpRules(UnicodeString& result) {
1103  UChar digitString[16];
1104 
1105  if ( ruleHeader != nullptr ) {
1106  result += fKeyword;
1107  result += COLON;
1108  result += SPACE;
1109  OrConstraint* orRule=ruleHeader;
1110  while ( orRule != nullptr ) {
1111  AndConstraint* andRule=orRule->childNode;
1112  while ( andRule != nullptr ) {
1113  if ((andRule->op==AndConstraint::NONE) && (andRule->rangeList==nullptr) && (andRule->value == -1)) {
1114  // Empty Rules.
1115  } else if ( (andRule->op==AndConstraint::NONE) && (andRule->rangeList==nullptr) ) {
1116  result += tokenString(andRule->digitsType);
1117  result += UNICODE_STRING_SIMPLE(" is ");
1118  if (andRule->negated) {
1119  result += UNICODE_STRING_SIMPLE("not ");
1120  }
1121  uprv_itou(digitString,16, andRule->value,10,0);
1122  result += UnicodeString(digitString);
1123  }
1124  else {
1125  result += tokenString(andRule->digitsType);
1126  result += SPACE;
1127  if (andRule->op==AndConstraint::MOD) {
1128  result += UNICODE_STRING_SIMPLE("mod ");
1129  uprv_itou(digitString,16, andRule->opNum,10,0);
1130  result += UnicodeString(digitString);
1131  }
1132  if (andRule->rangeList==nullptr) {
1133  if (andRule->negated) {
1134  result += UNICODE_STRING_SIMPLE(" is not ");
1135  uprv_itou(digitString,16, andRule->value,10,0);
1136  result += UnicodeString(digitString);
1137  }
1138  else {
1139  result += UNICODE_STRING_SIMPLE(" is ");
1140  uprv_itou(digitString,16, andRule->value,10,0);
1141  result += UnicodeString(digitString);
1142  }
1143  }
1144  else {
1145  if (andRule->negated) {
1146  if ( andRule->integerOnly ) {
1147  result += UNICODE_STRING_SIMPLE(" not in ");
1148  }
1149  else {
1150  result += UNICODE_STRING_SIMPLE(" not within ");
1151  }
1152  }
1153  else {
1154  if ( andRule->integerOnly ) {
1155  result += UNICODE_STRING_SIMPLE(" in ");
1156  }
1157  else {
1158  result += UNICODE_STRING_SIMPLE(" within ");
1159  }
1160  }
1161  for (int32_t r=0; r<andRule->rangeList->size(); r+=2) {
1162  int32_t rangeLo = andRule->rangeList->elementAti(r);
1163  int32_t rangeHi = andRule->rangeList->elementAti(r+1);
1164  uprv_itou(digitString,16, rangeLo, 10, 0);
1165  result += UnicodeString(digitString);
1166  result += UNICODE_STRING_SIMPLE("..");
1167  uprv_itou(digitString,16, rangeHi, 10,0);
1168  result += UnicodeString(digitString);
1169  if (r+2 < andRule->rangeList->size()) {
1170  result += UNICODE_STRING_SIMPLE(", ");
1171  }
1172  }
1173  }
1174  }
1175  if ( (andRule=andRule->next) != nullptr) {
1176  result += UNICODE_STRING_SIMPLE(" and ");
1177  }
1178  }
1179  if ( (orRule = orRule->next) != nullptr ) {
1180  result += UNICODE_STRING_SIMPLE(" or ");
1181  }
1182  }
1183  }
1184  if ( fNext != nullptr ) {
1185  result += UNICODE_STRING_SIMPLE("; ");
1187  }
1188 }
1189 
1190 
1191 UErrorCode
1192 RuleChain::getKeywords(int32_t capacityOfKeywords, UnicodeString* keywords, int32_t& arraySize) const {
1193  if (U_FAILURE(fInternalStatus)) {
1194  return fInternalStatus;
1195  }
1196  if ( arraySize < capacityOfKeywords-1 ) {
1197  keywords[arraySize++]=fKeyword;
1198  }
1199  else {
1200  return U_BUFFER_OVERFLOW_ERROR;
1201  }
1202 
1203  if ( fNext != nullptr ) {
1204  return fNext->getKeywords(capacityOfKeywords, keywords, arraySize);
1205  }
1206  else {
1207  return U_ZERO_ERROR;
1208  }
1209 }
1210 
1211 UBool
1212 RuleChain::isKeyword(const UnicodeString& keywordParam) const {
1213  if ( fKeyword == keywordParam ) {
1214  return TRUE;
1215  }
1216 
1217  if ( fNext != nullptr ) {
1218  return fNext->isKeyword(keywordParam);
1219  }
1220  else {
1221  return FALSE;
1222  }
1223 }
1224 
1225 
1227  ruleIndex(0), token(), type(none), prevType(none),
1228  curAndConstraint(nullptr), currentChain(nullptr), rangeLowIdx(-1), rangeHiIdx(-1)
1229 {
1230 }
1231 
1233 }
1234 
1235 
1236 int32_t
1238  int32_t i;
1239  char digits[128];
1240 
1241  i = token.extract(0, token.length(), digits, UPRV_LENGTHOF(digits), US_INV);
1242  digits[i]='\0';
1243 
1244  return((int32_t)atoi(digits));
1245 }
1246 
1247 
1248 void
1250 {
1251  if (U_FAILURE(status)) {
1252  return;
1253  }
1254  if (!(prevType==none || prevType==tSemiColon)) {
1255  type = getKeyType(token, type); // Switch token type from tKeyword if we scanned a reserved word,
1256  // and we are not at the start of a rule, where a
1257  // keyword is expected.
1258  }
1259 
1260  switch(prevType) {
1261  case none:
1262  case tSemiColon:
1263  if (type!=tKeyword && type != tEOF) {
1265  }
1266  break;
1267  case tVariableN:
1268  case tVariableI:
1269  case tVariableF:
1270  case tVariableT:
1271  case tVariableE:
1272  case tVariableV:
1273  if (type != tIs && type != tMod && type != tIn &&
1274  type != tNot && type != tWithin && type != tEqual && type != tNotEqual) {
1276  }
1277  break;
1278  case tKeyword:
1279  if (type != tColon) {
1281  }
1282  break;
1283  case tColon:
1284  if (!(type == tVariableN ||
1285  type == tVariableI ||
1286  type == tVariableF ||
1287  type == tVariableT ||
1288  type == tVariableE ||
1289  type == tVariableV ||
1290  type == tAt)) {
1292  }
1293  break;
1294  case tIs:
1295  if ( type != tNumber && type != tNot) {
1297  }
1298  break;
1299  case tNot:
1300  if (type != tNumber && type != tIn && type != tWithin) {
1302  }
1303  break;
1304  case tMod:
1305  case tDot2:
1306  case tIn:
1307  case tWithin:
1308  case tEqual:
1309  case tNotEqual:
1310  if (type != tNumber) {
1312  }
1313  break;
1314  case tAnd:
1315  case tOr:
1316  if ( type != tVariableN &&
1317  type != tVariableI &&
1318  type != tVariableF &&
1319  type != tVariableT &&
1320  type != tVariableE &&
1321  type != tVariableV) {
1323  }
1324  break;
1325  case tComma:
1326  if (type != tNumber) {
1328  }
1329  break;
1330  case tNumber:
1331  if (type != tDot2 && type != tSemiColon && type != tIs && type != tNot &&
1332  type != tIn && type != tEqual && type != tNotEqual && type != tWithin &&
1333  type != tAnd && type != tOr && type != tComma && type != tAt &&
1334  type != tEOF)
1335  {
1337  }
1338  // TODO: a comma following a number that is not part of a range will be allowed.
1339  // It's not the only case of this sort of thing. Parser needs a re-write.
1340  break;
1341  case tAt:
1342  if (type != tDecimal && type != tInteger) {
1344  }
1345  break;
1346  default:
1348  break;
1349  }
1350 }
1351 
1352 
1353 /*
1354  * Scan the next token from the input rules.
1355  * rules and returned token type are in the parser state variables.
1356  */
1357 void
1359 {
1360  if (U_FAILURE(status)) {
1361  return;
1362  }
1363 
1364  UChar ch;
1365  while (ruleIndex < ruleSrc->length()) {
1366  ch = ruleSrc->charAt(ruleIndex);
1367  type = charType(ch);
1368  if (type != tSpace) {
1369  break;
1370  }
1371  ++(ruleIndex);
1372  }
1373  if (ruleIndex >= ruleSrc->length()) {
1374  type = tEOF;
1375  return;
1376  }
1377  int32_t curIndex= ruleIndex;
1378 
1379  switch (type) {
1380  case tColon:
1381  case tSemiColon:
1382  case tComma:
1383  case tEllipsis:
1384  case tTilde: // scanned '~'
1385  case tAt: // scanned '@'
1386  case tEqual: // scanned '='
1387  case tMod: // scanned '%'
1388  // Single character tokens.
1389  ++curIndex;
1390  break;
1391 
1392  case tNotEqual: // scanned '!'
1393  if (ruleSrc->charAt(curIndex+1) == EQUALS) {
1394  curIndex += 2;
1395  } else {
1396  type = none;
1397  curIndex += 1;
1398  }
1399  break;
1400 
1401  case tKeyword:
1402  while (type == tKeyword && ++curIndex < ruleSrc->length()) {
1403  ch = ruleSrc->charAt(curIndex);
1404  type = charType(ch);
1405  }
1406  type = tKeyword;
1407  break;
1408 
1409  case tNumber:
1410  while (type == tNumber && ++curIndex < ruleSrc->length()) {
1411  ch = ruleSrc->charAt(curIndex);
1412  type = charType(ch);
1413  }
1414  type = tNumber;
1415  break;
1416 
1417  case tDot:
1418  // We could be looking at either ".." in a range, or "..." at the end of a sample.
1419  if (curIndex+1 >= ruleSrc->length() || ruleSrc->charAt(curIndex+1) != DOT) {
1420  ++curIndex;
1421  break; // Single dot
1422  }
1423  if (curIndex+2 >= ruleSrc->length() || ruleSrc->charAt(curIndex+2) != DOT) {
1424  curIndex += 2;
1425  type = tDot2;
1426  break; // double dot
1427  }
1428  type = tEllipsis;
1429  curIndex += 3;
1430  break; // triple dot
1431 
1432  default:
1434  ++curIndex;
1435  break;
1436  }
1437 
1438  U_ASSERT(ruleIndex <= ruleSrc->length());
1439  U_ASSERT(curIndex <= ruleSrc->length());
1440  token=UnicodeString(*ruleSrc, ruleIndex, curIndex-ruleIndex);
1441  ruleIndex = curIndex;
1442 }
1443 
1444 tokenType
1446  if ((ch>=U_ZERO) && (ch<=U_NINE)) {
1447  return tNumber;
1448  }
1449  if (ch>=LOW_A && ch<=LOW_Z) {
1450  return tKeyword;
1451  }
1452  switch (ch) {
1453  case COLON:
1454  return tColon;
1455  case SPACE:
1456  return tSpace;
1457  case SEMI_COLON:
1458  return tSemiColon;
1459  case DOT:
1460  return tDot;
1461  case COMMA:
1462  return tComma;
1463  case EXCLAMATION:
1464  return tNotEqual;
1465  case EQUALS:
1466  return tEqual;
1467  case PERCENT_SIGN:
1468  return tMod;
1469  case AT:
1470  return tAt;
1471  case ELLIPSIS:
1472  return tEllipsis;
1473  case TILDE:
1474  return tTilde;
1475  default :
1476  return none;
1477  }
1478 }
1479 
1480 
1481 // Set token type for reserved words in the Plural Rule syntax.
1482 
1483 tokenType
1484 PluralRuleParser::getKeyType(const UnicodeString &token, tokenType keyType)
1485 {
1486  if (keyType != tKeyword) {
1487  return keyType;
1488  }
1489 
1490  if (0 == token.compare(PK_VAR_N, 1)) {
1491  keyType = tVariableN;
1492  } else if (0 == token.compare(PK_VAR_I, 1)) {
1493  keyType = tVariableI;
1494  } else if (0 == token.compare(PK_VAR_F, 1)) {
1495  keyType = tVariableF;
1496  } else if (0 == token.compare(PK_VAR_T, 1)) {
1497  keyType = tVariableT;
1498  } else if (0 == token.compare(PK_VAR_E, 1)) {
1499  keyType = tVariableE;
1500  } else if (0 == token.compare(PK_VAR_V, 1)) {
1501  keyType = tVariableV;
1502  } else if (0 == token.compare(PK_IS, 2)) {
1503  keyType = tIs;
1504  } else if (0 == token.compare(PK_AND, 3)) {
1505  keyType = tAnd;
1506  } else if (0 == token.compare(PK_IN, 2)) {
1507  keyType = tIn;
1508  } else if (0 == token.compare(PK_WITHIN, 6)) {
1509  keyType = tWithin;
1510  } else if (0 == token.compare(PK_NOT, 3)) {
1511  keyType = tNot;
1512  } else if (0 == token.compare(PK_MOD, 3)) {
1513  keyType = tMod;
1514  } else if (0 == token.compare(PK_OR, 2)) {
1515  keyType = tOr;
1516  } else if (0 == token.compare(PK_DECIMAL, 7)) {
1517  keyType = tDecimal;
1518  } else if (0 == token.compare(PK_INTEGER, 7)) {
1519  keyType = tInteger;
1520  }
1521  return keyType;
1522 }
1523 
1524 
1526  : pos(0), fKeywordNames(status) {
1527  if (U_FAILURE(status)) {
1528  return;
1529  }
1531  UBool addKeywordOther = TRUE;
1532  RuleChain *node = header;
1533  while (node != nullptr) {
1534  auto newElem = new UnicodeString(node->fKeyword);
1535  if (newElem == nullptr) {
1537  return;
1538  }
1539  fKeywordNames.addElement(newElem, status);
1540  if (U_FAILURE(status)) {
1541  delete newElem;
1542  return;
1543  }
1544  if (0 == node->fKeyword.compare(PLURAL_KEYWORD_OTHER, 5)) {
1545  addKeywordOther = FALSE;
1546  }
1547  node = node->fNext;
1548  }
1549 
1550  if (addKeywordOther) {
1551  auto newElem = new UnicodeString(PLURAL_KEYWORD_OTHER);
1552  if (newElem == nullptr) {
1554  return;
1555  }
1556  fKeywordNames.addElement(newElem, status);
1557  if (U_FAILURE(status)) {
1558  delete newElem;
1559  return;
1560  }
1561  }
1562 }
1563 
1564 const UnicodeString*
1566  if (U_SUCCESS(status) && pos < fKeywordNames.size()) {
1567  return (const UnicodeString*)fKeywordNames.elementAt(pos++);
1568  }
1569  return nullptr;
1570 }
1571 
1572 void
1574  pos=0;
1575 }
1576 
1577 int32_t
1579  return fKeywordNames.size();
1580 }
1581 
1583 }
1584 
1586  switch(tt) {
1587  case tVariableN:
1588  return PLURAL_OPERAND_N;
1589  case tVariableI:
1590  return PLURAL_OPERAND_I;
1591  case tVariableF:
1592  return PLURAL_OPERAND_F;
1593  case tVariableV:
1594  return PLURAL_OPERAND_V;
1595  case tVariableT:
1596  return PLURAL_OPERAND_T;
1597  case tVariableE:
1598  return PLURAL_OPERAND_E;
1599  default:
1600  UPRV_UNREACHABLE; // unexpected.
1601  }
1602 }
1603 
1605  init(n, v, f, e);
1606  // check values. TODO make into unit test.
1607  //
1608  // long visiblePower = (int) Math.pow(10, v);
1609  // if (decimalDigits > visiblePower) {
1610  // throw new IllegalArgumentException();
1611  // }
1612  // double fraction = intValue + (decimalDigits / (double) visiblePower);
1613  // if (fraction != source) {
1614  // double diff = Math.abs(fraction - source)/(Math.abs(fraction) + Math.abs(source));
1615  // if (diff > 0.00000001d) {
1616  // throw new IllegalArgumentException();
1617  // }
1618  // }
1619 }
1620 
1622  init(n, v, f);
1623 }
1624 
1626  // Ugly, but for samples we don't care.
1627  init(n, v, getFractionalDigits(n, v));
1628 }
1629 
1631  init(n);
1632 }
1633 
1635  init(0, 0, 0);
1636 }
1637 
1638 
1639 // Create a FixedDecimal from a UnicodeString containing a number.
1640 // Inefficient, but only used for samples, so simplicity trumps efficiency.
1641 
1643  CharString cs;
1644  int32_t parsedExponent = 0;
1645 
1646  int32_t exponentIdx = num.indexOf(u'e');
1647  if (exponentIdx < 0) {
1648  exponentIdx = num.indexOf(u'E');
1649  }
1650  if (exponentIdx >= 0) {
1651  cs.appendInvariantChars(num.tempSubString(0, exponentIdx), status);
1652  int32_t expSubstrStart = exponentIdx + 1;
1653  parsedExponent = ICU_Utility::parseAsciiInteger(num, expSubstrStart);
1654  }
1655  else {
1656  cs.appendInvariantChars(num, status);
1657  }
1658 
1659  DecimalQuantity dl;
1660  dl.setToDecNumber(cs.toStringPiece(), status);
1661  if (U_FAILURE(status)) {
1662  init(0, 0, 0);
1663  return;
1664  }
1665 
1666  int32_t decimalPoint = num.indexOf(DOT);
1667  double n = dl.toDouble();
1668  if (decimalPoint == -1) {
1669  init(n, 0, 0, parsedExponent);
1670  } else {
1671  int32_t fractionNumLength = exponentIdx < 0 ? num.length() : cs.length();
1672  int32_t v = fractionNumLength - decimalPoint - 1;
1673  init(n, v, getFractionalDigits(n, v), parsedExponent);
1674  }
1675 }
1676 
1677 
1679  source = other.source;
1680  visibleDecimalDigitCount = other.visibleDecimalDigitCount;
1681  decimalDigits = other.decimalDigits;
1682  decimalDigitsWithoutTrailingZeros = other.decimalDigitsWithoutTrailingZeros;
1683  intValue = other.intValue;
1684  exponent = other.exponent;
1685  _hasIntegerValue = other._hasIntegerValue;
1686  isNegative = other.isNegative;
1687  _isNaN = other._isNaN;
1688  _isInfinite = other._isInfinite;
1689 }
1690 
1691 FixedDecimal::~FixedDecimal() = default;
1692 
1694  return FixedDecimal(n, v, getFractionalDigits(n, v), e);
1695 }
1696 
1697 
1698 void FixedDecimal::init(double n) {
1699  int32_t numFractionDigits = decimals(n);
1700  init(n, numFractionDigits, getFractionalDigits(n, numFractionDigits));
1701 }
1702 
1703 
1705  int32_t exponent = 0;
1706  init(n, v, f, exponent);
1707 }
1708 
1709 
1711  isNegative = n < 0.0;
1712  source = fabs(n);
1715  exponent = e;
1716  if (_isNaN || _isInfinite) {
1717  v = 0;
1718  f = 0;
1719  intValue = 0;
1721  } else {
1722  intValue = (int64_t)source;
1724  }
1725 
1727  decimalDigits = f;
1728  if (f == 0) {
1730  } else {
1731  int64_t fdwtz = f;
1732  while ((fdwtz%10) == 0) {
1733  fdwtz /= 10;
1734  }
1736  }
1737 }
1738 
1739 
1740 // Fast path only exact initialization. Return true if successful.
1741 // Note: Do not multiply by 10 each time through loop, rounding cruft can build
1742 // up that makes the check for an integer result fail.
1743 // A single multiply of the original number works more reliably.
1744 static int32_t p10[] = {1, 10, 100, 1000, 10000};
1746  UBool success = FALSE;
1747  n = fabs(n);
1748  int32_t numFractionDigits;
1749  for (numFractionDigits = 0; numFractionDigits <= 3; numFractionDigits++) {
1750  double scaledN = n * p10[numFractionDigits];
1751  if (scaledN == floor(scaledN)) {
1752  success = TRUE;
1753  break;
1754  }
1755  }
1756  if (success) {
1757  init(n, numFractionDigits, getFractionalDigits(n, numFractionDigits));
1758  }
1759  return success;
1760 }
1761 
1762 
1763 
1765  // Count the number of decimal digits in the fraction part of the number, excluding trailing zeros.
1766  // fastpath the common cases, integers or fractions with 3 or fewer digits
1767  n = fabs(n);
1768  for (int ndigits=0; ndigits<=3; ndigits++) {
1769  double scaledN = n * p10[ndigits];
1770  if (scaledN == floor(scaledN)) {
1771  return ndigits;
1772  }
1773  }
1774 
1775  // Slow path, convert with sprintf, parse converted output.
1776  char buf[30] = {0};
1777  sprintf(buf, "%1.15e", n);
1778  // formatted number looks like this: 1.234567890123457e-01
1779  int exponent = atoi(buf+18);
1780  int numFractionDigits = 15;
1781  for (int i=16; ; --i) {
1782  if (buf[i] != '0') {
1783  break;
1784  }
1785  --numFractionDigits;
1786  }
1787  numFractionDigits -= exponent; // Fraction part of fixed point representation.
1788  return numFractionDigits;
1789 }
1790 
1791 
1792 // Get the fraction digits of a double, represented as an integer.
1793 // v is the number of visible fraction digits in the displayed form of the number.
1794 // Example: n = 1001.234, v = 6, result = 234000
1795 // TODO: need to think through how this is used in the plural rule context.
1796 // This function can easily encounter integer overflow,
1797 // and can easily return noise digits when the precision of a double is exceeded.
1798 
1800  if (v == 0 || n == floor(n) || uprv_isNaN(n) || uprv_isPositiveInfinity(n)) {
1801  return 0;
1802  }
1803  n = fabs(n);
1804  double fract = n - floor(n);
1805  switch (v) {
1806  case 1: return (int64_t)(fract*10.0 + 0.5);
1807  case 2: return (int64_t)(fract*100.0 + 0.5);
1808  case 3: return (int64_t)(fract*1000.0 + 0.5);
1809  default:
1810  double scaled = floor(fract * pow(10.0, (double)v) + 0.5);
1811  if (scaled >= static_cast<double>(U_INT64_MAX)) {
1812  // Note: a double cannot accurately represent U_INT64_MAX. Casting it to double
1813  // will round up to the next representable value, which is U_INT64_MAX + 1.
1814  return U_INT64_MAX;
1815  } else {
1816  return (int64_t)scaled;
1817  }
1818  }
1819 }
1820 
1821 
1823  int32_t numTrailingFractionZeros = minFractionDigits - visibleDecimalDigitCount;
1824  if (numTrailingFractionZeros > 0) {
1825  for (int32_t i=0; i<numTrailingFractionZeros; i++) {
1826  // Do not let the decimalDigits value overflow if there are many trailing zeros.
1827  // Limit the value to 18 digits, the most that a 64 bit int can fully represent.
1828  if (decimalDigits >= 100000000000000000LL) {
1829  break;
1830  }
1831  decimalDigits *= 10;
1832  }
1833  visibleDecimalDigitCount += numTrailingFractionZeros;
1834  }
1835 }
1836 
1837 
1839  switch(operand) {
1840  case PLURAL_OPERAND_N: return source;
1841  case PLURAL_OPERAND_I: return static_cast<double>(intValue);
1842  case PLURAL_OPERAND_F: return static_cast<double>(decimalDigits);
1843  case PLURAL_OPERAND_T: return static_cast<double>(decimalDigitsWithoutTrailingZeros);
1845  case PLURAL_OPERAND_E: return exponent;
1846  default:
1847  UPRV_UNREACHABLE; // unexpected.
1848  }
1849 }
1850 
1851 bool FixedDecimal::isNaN() const {
1852  return _isNaN;
1853 }
1854 
1856  return _isInfinite;
1857 }
1858 
1860  return _hasIntegerValue;
1861 }
1862 
1864  return _isNaN || _isInfinite;
1865 }
1866 
1868  return visibleDecimalDigitCount;
1869 }
1870 
1872  return source == other.source && visibleDecimalDigitCount == other.visibleDecimalDigitCount
1873  && decimalDigits == other.decimalDigits && exponent == other.exponent;
1874 }
1875 
1876 UnicodeString FixedDecimal::toString() const {
1877  char pattern[15];
1878  char buffer[20];
1879  if (exponent == 0) {
1880  snprintf(pattern, sizeof(pattern), "%%.%df", visibleDecimalDigitCount);
1881  snprintf(buffer, sizeof(buffer), pattern, source);
1882  } else {
1883  snprintf(pattern, sizeof(pattern), "%%.%dfe%%d", visibleDecimalDigitCount);
1885  }
1886  return UnicodeString(buffer, -1, US_INV);
1887 }
1888 
1889 
1891  fOpenStatus = status;
1892  if (U_FAILURE(status)) {
1893  return;
1894  }
1895  fOpenStatus = U_ZERO_ERROR; // clear any warnings.
1896  LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "plurals", &fOpenStatus));
1897  fLocales = ures_getByKey(rb.getAlias(), "locales", nullptr, &fOpenStatus);
1898 }
1899 
1902  ures_close(fRes);
1903  fLocales = nullptr;
1904  fRes = nullptr;
1905 }
1906 
1908  if (U_FAILURE(status)) {
1909  return nullptr;
1910  }
1911  if (U_FAILURE(fOpenStatus)) {
1912  status = fOpenStatus;
1913  return nullptr;
1914  }
1916  if (fRes == nullptr || U_FAILURE(status)) {
1918  status = U_ZERO_ERROR;
1919  }
1920  return nullptr;
1921  }
1922  const char *result = ures_getKey(fRes);
1923  if (resultLength != nullptr) {
1924  *resultLength = static_cast<int32_t>(uprv_strlen(result));
1925  }
1926  return result;
1927 }
1928 
1929 
1931  if (U_FAILURE(status)) {
1932  return;
1933  }
1934  if (U_FAILURE(fOpenStatus)) {
1935  status = fOpenStatus;
1936  return;
1937  }
1939 }
1940 
1942  if (U_FAILURE(status)) {
1943  return 0;
1944  }
1945  if (U_FAILURE(fOpenStatus)) {
1946  status = fOpenStatus;
1947  return 0;
1948  }
1949  return ures_getSize(fLocales);
1950 }
1951 
1953 
1954 
1955 #endif /* #if !UCONFIG_NO_FORMATTING */
1956 
1957 //eof
double __cdecl fmod(double _X, double _Y)
double __cdecl pow(double _X, double _Y)
static int pr(int(*writeFunc)(void *stream, const char *data, int size), void *stream, const char *data)
Definition: HTMLGen.cc:249
integer fract(integer x, integer n, integer d, integer max_answer)
Definition: aptex-src.c:38726
#define type(a)
Definition: aptex-macros.h:171
int rc
Definition: bmpfont.h:9
GtkWidget * newSample(const gchar *fileName)
Definition: cgnomelayout.c:230
virtual ~AndConstraint()
Definition: plurrule.cpp:901
AndConstraint * next
AndConstraint()=default
AndConstraint * add(UErrorCode &status)
Definition: plurrule.cpp:950
UErrorCode fInternalStatus
UBool isFulfilled(const IFixedDecimal &number)
Definition: plurrule.cpp:909
tokenType digitsType
UVector32 * rangeList
int32_t visibleDecimalDigitCount
int32_t exponent
void init(double n, int32_t v, int64_t f, int32_t e)
Definition: plurrule.cpp:1710
int32_t getVisibleFractionDigitCount() const
Definition: plurrule.cpp:1867
int64_t decimalDigits
static int64_t getFractionalDigits(double n, int32_t v)
Definition: plurrule.cpp:1799
int64_t intValue
UBool _hasIntegerValue
UBool quickInit(double n)
Definition: plurrule.cpp:1745
static int32_t decimals(double n)
Definition: plurrule.cpp:1764
Bool__ hasIntegerValue() const override
Definition: plurrule.cpp:1859
void adjustForMinFractionDigits(int32_t min)
Definition: plurrule.cpp:1822
Bool__ isInfinite() const override
Definition: plurrule.cpp:1855
Bool__ operator==(const FixedDecimal &other) const
Definition: plurrule.cpp:1871
static FixedDecimal createWithExponent(double n, int32_t v, int32_t e)
Definition: plurrule.cpp:1693
Bool__ isNaN() const override
Definition: plurrule.cpp:1851
~FixedDecimal() override
Bool__ isNanOrInfinity() const
Definition: plurrule.cpp:1863
UnicodeString toString() const
Definition: plurrule.cpp:1876
double getPluralOperand(PluralOperand operand) const override
Definition: plurrule.cpp:1838
int64_t decimalDigitsWithoutTrailingZeros
static UnicodeString makeBogusString()
Definition: util.h:50
static int32_t parseAsciiInteger(const UnicodeString &str, int32_t &pos)
Definition: util.cpp:279
virtual const T * createObject(const void *creationContext, UErrorCode &status) const
virtual ~OrConstraint()
Definition: plurrule.cpp:987
OrConstraint()=default
UErrorCode fInternalStatus
AndConstraint * add(UErrorCode &status)
Definition: plurrule.cpp:995
UBool isFulfilled(const IFixedDecimal &number)
Definition: plurrule.cpp:1015
OrConstraint * next
AndConstraint * childNode
virtual int32_t count(UErrorCode &status) const
Definition: plurrule.cpp:1941
virtual void reset(UErrorCode &status)
Definition: plurrule.cpp:1930
virtual const char * next(int32_t *resultLength, UErrorCode &status)
Definition: plurrule.cpp:1907
PluralAvailableLocalesEnumeration(UErrorCode &status)
Definition: plurrule.cpp:1890
virtual const UnicodeString * snext(UErrorCode &status)
Definition: plurrule.cpp:1565
virtual int32_t count(UErrorCode &status) const
Definition: plurrule.cpp:1578
virtual ~PluralKeywordEnumeration()
Definition: plurrule.cpp:1582
virtual void reset(UErrorCode &status)
Definition: plurrule.cpp:1573
PluralKeywordEnumeration(RuleChain *header, UErrorCode &status)
Definition: plurrule.cpp:1525
virtual ~PluralRuleParser()
Definition: plurrule.cpp:1232
const UnicodeString * ruleSrc
static int32_t getNumberValue(const UnicodeString &token)
Definition: plurrule.cpp:1237
static tokenType getKeyType(const UnicodeString &token, tokenType type)
Definition: plurrule.cpp:1484
UnicodeString token
void parse(const UnicodeString &rules, PluralRules *dest, UErrorCode &status)
Definition: plurrule.cpp:587
tokenType prevType
void getNextToken(UErrorCode &status)
Definition: plurrule.cpp:1358
AndConstraint * curAndConstraint
static tokenType charType(UChar ch)
Definition: plurrule.cpp:1445
RuleChain * currentChain
void checkSyntax(UErrorCode &status)
Definition: plurrule.cpp:1249
UErrorCode fInternalStatus
UBool fIntegerSamplesUnbounded
UnicodeString select(const IFixedDecimal &number) const
Definition: plurrule.cpp:1069
UBool isKeyword(const UnicodeString &keyword) const
Definition: plurrule.cpp:1212
UnicodeString fKeyword
void dumpRules(UnicodeString &result)
Definition: plurrule.cpp:1102
UErrorCode getKeywords(int32_t maxArraySize, UnicodeString *keywords, int32_t &arraySize) const
Definition: plurrule.cpp:1192
UBool fDecimalSamplesUnbounded
UnicodeString fDecimalSamples
UnicodeString fIntegerSamples
RuleChain()=default
virtual ~RuleChain()
Definition: plurrule.cpp:1063
RuleChain * fNext
OrConstraint * ruleHeader
void removeRef() const
virtual ~SharedPluralRules()
Definition: plurrule.cpp:93
LocalPointer< StandardPluralRanges > toPointer(UErrorCode &status) &&noexcept
static StandardPluralRanges forLocale(const Locale &locale, UErrorCode &status)
static Form fromString(const char *keyword, UErrorCode &errorCode)
static const char * getKeyword(Form p)
int32_t elementAti(int32_t index) const
Definition: uvectr32.h:223
void addElement(int32_t elem, UErrorCode &status)
Definition: uvectr32.h:228
void setElementAt(int32_t elem, int32_t index)
Definition: uvectr32.cpp:98
void assign(const UVector32 &other, UErrorCode &ec)
Definition: uvectr32.cpp:76
int32_t size(void) const
Definition: uvectr32.h:255
int32_t size(void) const
Definition: uvector.h:353
void * elementAt(int32_t index) const
Definition: uvector.cpp:188
UObjectDeleter * setDeleter(UObjectDeleter *d)
Definition: uvector.cpp:403
void addElement(void *obj, UErrorCode &status)
Definition: uvector.cpp:127
static void getByLocale(const Locale &loc, const T *&ptr, UErrorCode &status)
Definition: unifiedcache.h:268
#define UPRV_LENGTHOF(array)
Definition: cmemory.h:50
#define n
Definition: t4ht.c:1290
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CompactDecimalFormat) CompactDecimalFormat *CompactDecimalFormat
#define uprv_strcpy(dst, src)
Definition: cstring.h:36
#define uprv_strlen(str)
Definition: cstring.h:37
#define none
Definition: ctie-k.c:30
@ FALSE
Definition: dd.h:101
@ TRUE
Definition: dd.h:102
static const char description[]
Definition: drvwmf.cpp:127
#define LOW_Z
Definition: dt_impl.h:65
#define LOW_E
Definition: dt_impl.h:45
#define LOW_W
Definition: dt_impl.h:63
#define LOW_R
Definition: dt_impl.h:58
#define LOW_V
Definition: dt_impl.h:62
#define LOW_M
Definition: dt_impl.h:53
#define LOW_H
Definition: dt_impl.h:48
#define LOW_T
Definition: dt_impl.h:60
#define LOW_G
Definition: dt_impl.h:47
#define LOW_O
Definition: dt_impl.h:55
#define LOW_C
Definition: dt_impl.h:43
#define LOW_D
Definition: dt_impl.h:44
#define LOW_S
Definition: dt_impl.h:59
#define LOW_F
Definition: dt_impl.h:46
#define LOW_I
Definition: dt_impl.h:49
#define LOW_N
Definition: dt_impl.h:54
#define LOW_A
Definition: dt_impl.h:41
#define LOW_L
Definition: dt_impl.h:52
int v
Definition: dviconv.c:10
#define error(a)
Definition: dviinfo.c:48
mpz_t * f
Definition: gen-fib.c:34
#define SPACE
Definition: general.h:107
#define s
Definition: afcover.h:80
#define t
Definition: afcover.h:96
bool operator==(const GenBuffer &s1, const GenBuffer &s2)
Definition: gensi.hpp:671
#define d(n)
Definition: gpos-common.c:151
unsigned char UChar
Definition: bzip2.c:163
small capitals from c petite p scientific f u
Definition: afcover.h:88
small capitals from c petite p scientific i
Definition: afcover.h:80
signed __int64 int64_t
Definition: stdint.h:89
signed int int32_t
Definition: stdint.h:77
int atoi(const char *)
int num
Definition: disdvi.c:621
#define buf
#define fabs(x)
Definition: cpascal.h:211
#define floor(x)
Definition: cpascal.h:52
#define length(c)
Definition: ctangleboot.c:65
union hdr header
Definition: pbmtomacp.c:291
#define dest
#define sprintf
Definition: snprintf.c:44
#define snprintf
Definition: snprintf.c:41
#define U_EXPORT2
Definition: platform.h:844
#define U_FALLTHROUGH
Definition: platform.h:562
C++ API: "Smart pointers" for use with and in ICU4C C++ code.
const int * pos
Definition: combiners.h:905
@ other
Definition: mtxline.h:22
UnicodeString select(const PluralRules &rules, const Formattable &obj, const NumberFormat &fmt, UErrorCode &status)
static const UChar EXCLAMATION
Definition: plurrule_impl.h:58
static const UChar ELLIPSIS
Definition: plurrule_impl.h:87
unsigned digits[12]
Definition: out_routines.c:255
#define scaled
Definition: pdftypes.h:88
#define DOT
Definition: pgmtexture.c:65
#define AT
static const UChar PK_NOT[]
Definition: plurrule.cpp:53
static const UChar PK_WITHIN[]
Definition: plurrule.cpp:64
static int32_t getSamplesFromString(const UnicodeString &samples, double *destDbl, FixedDecimal *destFd, int32_t destCapacity, UErrorCode &status)
Definition: plurrule.cpp:387
static const UChar PK_IS[]
Definition: plurrule.cpp:54
static const UChar PK_VAR_V[]
Definition: plurrule.cpp:63
static const UChar PK_MOD[]
Definition: plurrule.cpp:55
static double scaleForInt(double d)
Definition: plurrule.cpp:372
static const UChar PK_INTEGER[]
Definition: plurrule.cpp:66
static const UChar PK_DECIMAL[]
Definition: plurrule.cpp:65
static int32_t p10[]
Definition: plurrule.cpp:1744
static const UChar PK_OR[]
Definition: plurrule.cpp:57
static const UChar PK_VAR_T[]
Definition: plurrule.cpp:61
static const UChar PK_VAR_N[]
Definition: plurrule.cpp:58
static const UChar PLURAL_DEFAULT_RULE[]
Definition: plurrule.cpp:51
static const UChar PK_AND[]
Definition: plurrule.cpp:56
PluralOperand tokenTypeToPluralOperand(tokenType tt)
Definition: plurrule.cpp:1585
static const UChar PK_VAR_F[]
Definition: plurrule.cpp:60
static const UChar PK_VAR_I[]
Definition: plurrule.cpp:59
static const UChar PK_VAR_E[]
Definition: plurrule.cpp:62
static const UChar PLURAL_KEYWORD_OTHER[]
Definition: plurrule.cpp:50
static UnicodeString tokenString(tokenType tok)
Definition: plurrule.cpp:1080
static const UChar PK_IN[]
Definition: plurrule.cpp:52
static const int32_t PLURAL_RANGE_HIGH
tokenType
@ tSpace
@ tInteger
@ tVariableI
@ tNotEqual
@ tVariableN
@ tIn
@ tDecimal
@ tVariableV
@ tDot
@ tEOF
@ tVariableT
@ tWithin
@ tVariableF
@ tAt
@ tOr
@ tComma
@ tAnd
@ tTilde
@ tMod
@ tNumber
@ tKeyword
@ tVariableE
@ tEllipsis
@ tEqual
@ tColon
@ tNot
@ tDot2
@ tSemiColon
@ tIs
PluralOperand
@ PLURAL_OPERAND_V
@ PLURAL_OPERAND_N
@ PLURAL_OPERAND_F
@ PLURAL_OPERAND_E
@ PLURAL_OPERAND_I
@ PLURAL_OPERAND_T
double scale
Definition: pnmhistmap.c:38
static struct colourSystem * cs
Definition: ppmcie.c:241
int r
Definition: ppmqvga.c:68
#define impl
Definition: pts_fax.c:34
#define status
le_int32 fixed
Definition: sfnt.h:144
#define U_NINE
Definition: selfmtimpl.h:49
#define U_ZERO
Definition: selfmtimpl.h:40
#define SEMI_COLON
Definition: selfmtimpl.h:51
ShellFileEnvironment e
Definition: sh6.c:388
#define int32_t
Definition: stdint.in.h:167
#define int64_t
Definition: stdint.in.h:194
UChar rules[100]
Definition: strsrch.cpp:66
Definition: utils.c:300
Definition: pst1form.c:310
Definition: sh.h:1226
Definition: ffi.h:208
Definition: sh.h:1345
Definition: dvips.h:235
Definition: parser.c:43
def_key keyword[6]
Definition: t1part.c:256
ch
Definition: t4ht.c:1443
#define key
Definition: tex2xindy.c:753
static int errCode
Definition: tex4ht.c:1090
#define U_ASSERT(exp)
Definition: uassert.h:37
#define UPRV_UNREACHABLE
Definition: uassert.h:48
#define COMMA
Definition: ucnv_u7.cpp:865
#define TILDE
Definition: ucnv_u7.cpp:95
#define ULOC_FULLNAME_CAPACITY
Definition: uloc.h:264
int8_t UBool
Definition: umachine.h:269
#define U_INT64_MAX
Definition: umachine.h:249
Definition: obx.h:51
#define EQUALS
Definition: uniset.cpp:49
C API: Plural rules, select plural keywords for numeric values.
UPluralType
Definition: upluralrules.h:58
@ UPLURAL_TYPE_ORDINAL
Definition: upluralrules.h:68
@ UPLURAL_TYPE_CARDINAL
Definition: upluralrules.h:63
@ UPLURAL_TYPE_COUNT
Definition: upluralrules.h:74
#define uprv_itou
Definition: urename.h:1433
#define uprv_deleteUObject
Definition: urename.h:1400
#define ures_getKey
Definition: urename.h:1576
#define uprv_isPositiveInfinity
Definition: urename.h:1432
#define uprv_isNaN
Definition: urename.h:1430
#define ures_getNextResource
Definition: urename.h:1582
#define ures_resetIterator
Definition: urename.h:1608
#define uloc_getParent
Definition: urename.h:1094
#define ures_getSize
Definition: urename.h:1584
#define ures_getByKey
Definition: urename.h:1571
#define ures_getStringByKey
Definition: urename.h:1587
#define uprv_isInfinite
Definition: urename.h:1427
#define uprv_floor
Definition: urename.h:1410
#define u_UCharsToChars
Definition: urename.h:205
#define ures_close
Definition: urename.h:1563
#define ures_openDirect
Definition: urename.h:1603
C API: Resource Bundle.
static const char * locale
Definition: uresb.c:52
@ range
Definition: preamble.c:52
Basic definitions for ICU, for both C and C++ APIs.
UErrorCode
Definition: utypes.h:431
@ U_MEMORY_ALLOCATION_ERROR
Definition: utypes.h:473
@ U_BUFFER_OVERFLOW_ERROR
Definition: utypes.h:481
@ U_ILLEGAL_ARGUMENT_ERROR
Definition: utypes.h:467
@ U_INVALID_FORMAT_ERROR
Definition: utypes.h:469
@ U_UNEXPECTED_TOKEN
Definition: utypes.h:567
@ U_UNSUPPORTED_ERROR
Definition: utypes.h:482
@ U_INDEX_OUTOFBOUNDS_ERROR
Definition: utypes.h:474
@ U_ZERO_ERROR
Definition: utypes.h:465
@ U_INTERNAL_PROGRAM_ERROR
Definition: utypes.h:471
#define U_FAILURE(x)
Definition: utypes.h:735
#define U_SUCCESS(x)
Definition: utypes.h:730
#define U_I18N_API
Definition: utypes.h:365
long long scaled
Definition: vf_ng.c:93
#define nullptr
Definition: xetex.h:75
static const char * tok(parser_state *p)
Definition: y.tab.c:10456