diff --git a/deps/icu-small/source/common/unicode/edits.h b/deps/icu-small/source/common/unicode/edits.h
index 5a72574c140db6..f767a8d3b494c3 100644
--- a/deps/icu-small/source/common/unicode/edits.h
+++ b/deps/icu-small/source/common/unicode/edits.h
@@ -17,10 +17,57 @@
U_NAMESPACE_BEGIN
+class UnicodeString;
+
/**
- * Records lengths of string edits but not replacement text.
- * Supports replacements, insertions, deletions in linear progression.
- * Does not support moving/reordering of text.
+ * Records lengths of string edits but not replacement text. Supports replacements, insertions, deletions
+ * in linear progression. Does not support moving/reordering of text.
+ *
+ * There are two types of edits: change edits and no-change edits. Add edits to
+ * instances of this class using {@link #addReplace(int, int)} (for change edits) and
+ * {@link #addUnchanged(int)} (for no-change edits). Change edits are retained with full granularity,
+ * whereas adjacent no-change edits are always merged together. In no-change edits, there is a one-to-one
+ * mapping between code points in the source and destination strings.
+ *
+ * After all edits have been added, instances of this class should be considered immutable, and an
+ * {@link Edits::Iterator} can be used for queries.
+ *
+ * There are four flavors of Edits::Iterator:
+ *
+ *
+ * - {@link #getFineIterator()} retains full granularity of change edits.
+ *
- {@link #getFineChangesIterator()} retains full granularity of change edits, and when calling
+ * next() on the iterator, skips over no-change edits (unchanged regions).
+ *
- {@link #getCoarseIterator()} treats adjacent change edits as a single edit. (Adjacent no-change
+ * edits are automatically merged during the construction phase.)
+ *
- {@link #getCoarseChangesIterator()} treats adjacent change edits as a single edit, and when
+ * calling next() on the iterator, skips over no-change edits (unchanged regions).
+ *
+ *
+ * For example, consider the string "abcßDeF", which case-folds to "abcssdef". This string has the
+ * following fine edits:
+ *
+ * - abc ⇨ abc (no-change)
+ *
- ß ⇨ ss (change)
+ *
- D ⇨ d (change)
+ *
- e ⇨ e (no-change)
+ *
- F ⇨ f (change)
+ *
+ * and the following coarse edits (note how adjacent change edits get merged together):
+ *
+ * - abc ⇨ abc (no-change)
+ *
- ßD ⇨ ssd (change)
+ *
- e ⇨ e (no-change)
+ *
- F ⇨ f (change)
+ *
+ *
+ * The "fine changes" and "coarse changes" iterators will step through only the change edits when their
+ * {@link Edits::Iterator#next()} methods are called. They are identical to the non-change iterators when
+ * their {@link Edits::Iterator#findSourceIndex(int)} or {@link Edits::Iterator#findDestinationIndex(int)}
+ * methods are used to walk through the string.
+ *
+ * For examples of how to use this class, see the test TestCaseMapEditsIteratorDocs
in
+ * UCharacterCaseTest.java.
*
* An Edits object tracks a separate UErrorCode, but ICU string transformation functions
* (e.g., case mapping functions) merge any such errors into their API's UErrorCode.
@@ -91,13 +138,13 @@ class U_COMMON_API Edits U_FINAL : public UMemory {
void reset() U_NOEXCEPT;
/**
- * Adds a record for an unchanged segment of text.
+ * Adds a no-change edit: a record for an unchanged segment of text.
* Normally called from inside ICU string transformation functions, not user code.
* @stable ICU 59
*/
void addUnchanged(int32_t unchangedLength);
/**
- * Adds a record for a text replacement/insertion/deletion.
+ * Adds a change edit: a record for a text replacement/insertion/deletion.
* Normally called from inside ICU string transformation functions, not user code.
* @stable ICU 59
*/
@@ -136,6 +183,18 @@ class U_COMMON_API Edits U_FINAL : public UMemory {
/**
* Access to the list of edits.
+ *
+ * At any moment in time, an instance of this class points to a single edit: a "window" into a span
+ * of the source string and the corresponding span of the destination string. The source string span
+ * starts at {@link #sourceIndex()} and runs for {@link #oldLength()} chars; the destination string
+ * span starts at {@link #destinationIndex()} and runs for {@link #newLength()} chars.
+ *
+ * The iterator can be moved between edits using the {@link #next()}, {@link #findSourceIndex(int)},
+ * and {@link #findDestinationIndex(int)} methods. Calling any of these methods mutates the iterator
+ * to make it point to the corresponding edit.
+ *
+ * For more information, see the documentation for {@link Edits}.
+ *
* @see getCoarseIterator
* @see getFineIterator
* @stable ICU 59
@@ -162,7 +221,7 @@ class U_COMMON_API Edits U_FINAL : public UMemory {
Iterator &operator=(const Iterator &other) = default;
/**
- * Advances to the next edit.
+ * Advances the iterator to the next edit.
* @param errorCode ICU error code. Its input value must pass the U_SUCCESS() test,
* or else the function returns immediately. Check for U_FAILURE()
* on output or use with function chaining. (See User Guide for details.)
@@ -172,9 +231,9 @@ class U_COMMON_API Edits U_FINAL : public UMemory {
UBool next(UErrorCode &errorCode) { return next(onlyChanges_, errorCode); }
/**
- * Finds the edit that contains the source index.
- * The source index may be found in a non-change
- * even if normal iteration would skip non-changes.
+ * Moves the iterator to the edit that contains the source index.
+ * The source index may be found in a no-change edit
+ * even if normal iteration would skip no-change edits.
* Normal iteration can continue from a found edit.
*
* The iterator state before this search logically does not matter.
@@ -196,9 +255,9 @@ class U_COMMON_API Edits U_FINAL : public UMemory {
#ifndef U_HIDE_DRAFT_API
/**
- * Finds the edit that contains the destination index.
- * The destination index may be found in a non-change
- * even if normal iteration would skip non-changes.
+ * Moves the iterator to the edit that contains the destination index.
+ * The destination index may be found in a no-change edit
+ * even if normal iteration would skip no-change edits.
* Normal iteration can continue from a found edit.
*
* The iterator state before this search logically does not matter.
@@ -219,7 +278,7 @@ class U_COMMON_API Edits U_FINAL : public UMemory {
}
/**
- * Returns the destination index corresponding to the given source index.
+ * Computes the destination index corresponding to the given source index.
* If the source index is inside a change edit (not at its start),
* then the destination index at the end of that edit is returned,
* since there is no information about index mapping inside a change edit.
@@ -243,7 +302,7 @@ class U_COMMON_API Edits U_FINAL : public UMemory {
int32_t destinationIndexFromSourceIndex(int32_t i, UErrorCode &errorCode);
/**
- * Returns the source index corresponding to the given destination index.
+ * Computes the source index corresponding to the given destination index.
* If the destination index is inside a change edit (not at its start),
* then the source index at the end of that edit is returned,
* since there is no information about index mapping inside a change edit.
@@ -268,17 +327,27 @@ class U_COMMON_API Edits U_FINAL : public UMemory {
#endif // U_HIDE_DRAFT_API
/**
+ * Returns whether the edit currently represented by the iterator is a change edit.
+ *
* @return TRUE if this edit replaces oldLength() units with newLength() different ones.
* FALSE if oldLength units remain unchanged.
* @stable ICU 59
*/
UBool hasChange() const { return changed; }
+
/**
+ * The length of the current span in the source string, which starts at {@link #sourceIndex}.
+ *
* @return the number of units in the original string which are replaced or remain unchanged.
* @stable ICU 59
*/
int32_t oldLength() const { return oldLength_; }
+
/**
+ * The length of the current span in the destination string, which starts at
+ * {@link #destinationIndex}, or in the replacement string, which starts at
+ * {@link #replacementIndex}.
+ *
* @return the number of units in the modified string, if hasChange() is TRUE.
* Same as oldLength if hasChange() is FALSE.
* @stable ICU 59
@@ -286,22 +355,52 @@ class U_COMMON_API Edits U_FINAL : public UMemory {
int32_t newLength() const { return newLength_; }
/**
+ * The start index of the current span in the source string; the span has length
+ * {@link #oldLength}.
+ *
* @return the current index into the source string
* @stable ICU 59
*/
int32_t sourceIndex() const { return srcIndex; }
+
/**
+ * The start index of the current span in the replacement string; the span has length
+ * {@link #newLength}. Well-defined only if the current edit is a change edit.
+ *
+ * The replacement string is the concatenation of all substrings of the destination
+ * string corresponding to change edits.
+ *
+ * This method is intended to be used together with operations that write only replacement
+ * characters (e.g., {@link CaseMap#omitUnchangedText()}). The source string can then be modified
+ * in-place.
+ *
* @return the current index into the replacement-characters-only string,
* not counting unchanged spans
* @stable ICU 59
*/
- int32_t replacementIndex() const { return replIndex; }
+ int32_t replacementIndex() const {
+ // TODO: Throw an exception if we aren't in a change edit?
+ return replIndex;
+ }
+
/**
+ * The start index of the current span in the destination string; the span has length
+ * {@link #newLength}.
+ *
* @return the current index into the full destination string
* @stable ICU 59
*/
int32_t destinationIndex() const { return destIndex; }
+#ifndef U_HIDE_INTERNAL_API
+ /**
+ * A string representation of the current edit represented by the iterator for debugging. You
+ * should not depend on the contents of the return string.
+ * @internal
+ */
+ UnicodeString& toString(UnicodeString& appendTo) const;
+#endif // U_HIDE_INTERNAL_API
+
private:
friend class Edits;
@@ -330,8 +429,10 @@ class U_COMMON_API Edits U_FINAL : public UMemory {
};
/**
- * Returns an Iterator for coarse-grained changes for simple string updates.
- * Skips non-changes.
+ * Returns an Iterator for coarse-grained change edits
+ * (adjacent change edits are treated as one).
+ * Can be used to perform simple string updates.
+ * Skips no-change edits.
* @return an Iterator that merges adjacent changes.
* @stable ICU 59
*/
@@ -340,7 +441,10 @@ class U_COMMON_API Edits U_FINAL : public UMemory {
}
/**
- * Returns an Iterator for coarse-grained changes and non-changes for simple string updates.
+ * Returns an Iterator for coarse-grained change and no-change edits
+ * (adjacent change edits are treated as one).
+ * Can be used to perform simple string updates.
+ * Adjacent change edits are treated as one edit.
* @return an Iterator that merges adjacent changes.
* @stable ICU 59
*/
@@ -349,8 +453,10 @@ class U_COMMON_API Edits U_FINAL : public UMemory {
}
/**
- * Returns an Iterator for fine-grained changes for modifying styled text.
- * Skips non-changes.
+ * Returns an Iterator for fine-grained change edits
+ * (full granularity of change edits is retained).
+ * Can be used for modifying styled text.
+ * Skips no-change edits.
* @return an Iterator that separates adjacent changes.
* @stable ICU 59
*/
@@ -359,7 +465,9 @@ class U_COMMON_API Edits U_FINAL : public UMemory {
}
/**
- * Returns an Iterator for fine-grained changes and non-changes for modifying styled text.
+ * Returns an Iterator for fine-grained change and no-change edits
+ * (full granularity of change edits is retained).
+ * Can be used for modifying styled text.
* @return an Iterator that separates adjacent changes.
* @stable ICU 59
*/
diff --git a/deps/icu-small/source/common/unicode/platform.h b/deps/icu-small/source/common/unicode/platform.h
index a3f8d32f89d2cd..d9636580c309b5 100644
--- a/deps/icu-small/source/common/unicode/platform.h
+++ b/deps/icu-small/source/common/unicode/platform.h
@@ -196,20 +196,6 @@
# define U_PLATFORM U_PF_UNKNOWN
#endif
-/**
- * \def UPRV_INCOMPLETE_CPP11_SUPPORT
- * This switch turns off ICU 60 NumberFormatter code.
- * By default, this switch is enabled on AIX and z/OS,
- * which have poor C++11 support.
- *
- * NOTE: This switch is intended to be temporary; see #13393.
- *
- * @internal
- */
-#ifndef UPRV_INCOMPLETE_CPP11_SUPPORT
-# define UPRV_INCOMPLETE_CPP11_SUPPORT (U_PLATFORM == U_PF_AIX || U_PLATFORM == U_PF_OS390 || U_PLATFORM == U_PF_SOLARIS )
-#endif
-
/**
* \def CYGWINMSVC
* Defined if this is Windows with Cygwin, but using MSVC rather than gcc.
diff --git a/deps/icu-small/source/common/unicode/rbbi.h b/deps/icu-small/source/common/unicode/rbbi.h
index 0c41d69d235ccb..e9b82cd520736b 100644
--- a/deps/icu-small/source/common/unicode/rbbi.h
+++ b/deps/icu-small/source/common/unicode/rbbi.h
@@ -55,7 +55,7 @@ class U_COMMON_API RuleBasedBreakIterator /*U_FINAL*/ : public BreakIterator {
private:
/**
* The UText through which this BreakIterator accesses the text
- * @internal
+ * @internal (private)
*/
UText fText;
@@ -70,13 +70,6 @@ class U_COMMON_API RuleBasedBreakIterator /*U_FINAL*/ : public BreakIterator {
RBBIDataWrapper *fData;
private:
- /**
- * The iteration state - current position, rule status for the current position,
- * and whether the iterator ran off the end, yielding UBRK_DONE.
- * Current position is pinned to be 0 < position <= text.length.
- * Current position is always set to a boundary.
- * @internal
- */
/**
* The current position of the iterator. Pinned, 0 < fPosition <= text.length.
* Never has the value UBRK_DONE (-1).
@@ -628,25 +621,26 @@ class U_COMMON_API RuleBasedBreakIterator /*U_FINAL*/ : public BreakIterator {
/**
* Dumps caches and performs other actions associated with a complete change
* in text or iteration position.
- * @internal
+ * @internal (private)
*/
void reset(void);
/**
* Common initialization function, used by constructors and bufferClone.
- * @internal
+ * @internal (private)
*/
void init(UErrorCode &status);
/**
- * Iterate backwards from an arbitrary position in the input text using the Safe Reverse rules.
+ * Iterate backwards from an arbitrary position in the input text using the
+ * synthesized Safe Reverse rules.
* This locates a "Safe Position" from which the forward break rules
* will operate correctly. A Safe Position is not necessarily a boundary itself.
*
* @param fromPosition the position in the input text to begin the iteration.
- * @internal
+ * @internal (private)
*/
- int32_t handlePrevious(int32_t fromPosition);
+ int32_t handleSafePrevious(int32_t fromPosition);
/**
* Find a rule-based boundary by running the state machine.
@@ -658,7 +652,7 @@ class U_COMMON_API RuleBasedBreakIterator /*U_FINAL*/ : public BreakIterator {
* If > 0, the segment will be further subdivided
* fRuleStatusIndex Info from the state table indicating which rules caused the boundary.
*
- * @internal
+ * @internal (private)
*/
int32_t handleNext();
@@ -667,7 +661,7 @@ class U_COMMON_API RuleBasedBreakIterator /*U_FINAL*/ : public BreakIterator {
* This function returns the appropriate LanguageBreakEngine for a
* given character c.
* @param c A character in the dictionary set
- * @internal
+ * @internal (private)
*/
const LanguageBreakEngine *getLanguageBreakEngine(UChar32 c);
diff --git a/deps/icu-small/source/common/unicode/uchar.h b/deps/icu-small/source/common/unicode/uchar.h
index 4b72ecfc26bf9a..6d31083e66ee0d 100644
--- a/deps/icu-small/source/common/unicode/uchar.h
+++ b/deps/icu-small/source/common/unicode/uchar.h
@@ -42,7 +42,7 @@ U_CDECL_BEGIN
* @see u_getUnicodeVersion
* @stable ICU 2.0
*/
-#define U_UNICODE_VERSION "10.0"
+#define U_UNICODE_VERSION "11.0"
/**
* \file
@@ -446,6 +446,13 @@ typedef enum UProperty {
* @stable ICU 60
*/
UCHAR_PREPENDED_CONCATENATION_MARK=63,
+ /**
+ * Binary property Extended_Pictographic.
+ * See http://www.unicode.org/reports/tr51/#Emoji_Properties
+ *
+ * @stable ICU 62
+ */
+ UCHAR_EXTENDED_PICTOGRAPHIC=64,
#ifndef U_HIDE_DEPRECATED_API
/**
* One more than the last constant for binary Unicode properties.
@@ -1683,6 +1690,31 @@ enum UBlockCode {
/** @stable ICU 60 */
UBLOCK_ZANABAZAR_SQUARE = 280, /*[11A00]*/
+ // New blocks in Unicode 11.0
+
+ /** @stable ICU 62 */
+ UBLOCK_CHESS_SYMBOLS = 281, /*[1FA00]*/
+ /** @stable ICU 62 */
+ UBLOCK_DOGRA = 282, /*[11800]*/
+ /** @stable ICU 62 */
+ UBLOCK_GEORGIAN_EXTENDED = 283, /*[1C90]*/
+ /** @stable ICU 62 */
+ UBLOCK_GUNJALA_GONDI = 284, /*[11D60]*/
+ /** @stable ICU 62 */
+ UBLOCK_HANIFI_ROHINGYA = 285, /*[10D00]*/
+ /** @stable ICU 62 */
+ UBLOCK_INDIC_SIYAQ_NUMBERS = 286, /*[1EC70]*/
+ /** @stable ICU 62 */
+ UBLOCK_MAKASAR = 287, /*[11EE0]*/
+ /** @stable ICU 62 */
+ UBLOCK_MAYAN_NUMERALS = 288, /*[1D2E0]*/
+ /** @stable ICU 62 */
+ UBLOCK_MEDEFAIDRIN = 289, /*[16E40]*/
+ /** @stable ICU 62 */
+ UBLOCK_OLD_SOGDIAN = 290, /*[10F00]*/
+ /** @stable ICU 62 */
+ UBLOCK_SOGDIAN = 291, /*[10F30]*/
+
#ifndef U_HIDE_DEPRECATED_API
/**
* One more than the highest normal UBlockCode value.
@@ -1690,7 +1722,7 @@ enum UBlockCode {
*
* @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420.
*/
- UBLOCK_COUNT = 281,
+ UBLOCK_COUNT = 292,
#endif // U_HIDE_DEPRECATED_API
/** @stable ICU 2.0 */
@@ -1979,6 +2011,9 @@ typedef enum UJoiningGroup {
U_JG_MALAYALAM_SSA, /**< @stable ICU 60 */
U_JG_MALAYALAM_TTA, /**< @stable ICU 60 */
+ U_JG_HANIFI_ROHINGYA_KINNA_YA, /**< @stable ICU 62 */
+ U_JG_HANIFI_ROHINGYA_PA, /**< @stable ICU 62 */
+
#ifndef U_HIDE_DEPRECATED_API
/**
* One more than the highest normal UJoiningGroup value.
@@ -2029,6 +2064,7 @@ typedef enum UGraphemeClusterBreak {
U_GCB_GLUE_AFTER_ZWJ = 16, /*[GAZ]*/
/** @stable ICU 58 */
U_GCB_ZWJ = 17, /*[ZWJ]*/
+
#ifndef U_HIDE_DEPRECATED_API
/**
* One more than the highest normal UGraphemeClusterBreak value.
@@ -2090,6 +2126,9 @@ typedef enum UWordBreakValues {
U_WB_GLUE_AFTER_ZWJ = 20, /*[GAZ]*/
/** @stable ICU 58 */
U_WB_ZWJ = 21, /*[ZWJ]*/
+ /** @stable ICU 62 */
+ U_WB_WSEGSPACE = 22, /*[WSEGSPACE]*/
+
#ifndef U_HIDE_DEPRECATED_API
/**
* One more than the highest normal UWordBreakValues value.
@@ -2097,7 +2136,7 @@ typedef enum UWordBreakValues {
*
* @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420.
*/
- U_WB_COUNT = 22
+ U_WB_COUNT = 23
#endif // U_HIDE_DEPRECATED_API
} UWordBreakValues;
diff --git a/deps/icu-small/source/common/unicode/unistr.h b/deps/icu-small/source/common/unicode/unistr.h
index d0b271754b660e..b84f40bd449ced 100644
--- a/deps/icu-small/source/common/unicode/unistr.h
+++ b/deps/icu-small/source/common/unicode/unistr.h
@@ -1892,7 +1892,7 @@ class U_COMMON_API UnicodeString : public Replaceable
UnicodeString &fastCopyFrom(const UnicodeString &src);
/**
- * Move assignment operator, might leave src in bogus state.
+ * Move assignment operator; might leave src in bogus state.
* This string will have the same contents and state that the source string had.
* The behavior is undefined if *this and src are the same object.
* @param src source string
@@ -1905,7 +1905,7 @@ class U_COMMON_API UnicodeString : public Replaceable
// do not use #ifndef U_HIDE_DRAFT_API for moveFrom, needed by non-draft API
/**
- * Move assignment, might leave src in bogus state.
+ * Move assignment; might leave src in bogus state.
* This string will have the same contents and state that the source string had.
* The behavior is undefined if *this and src are the same object.
*
@@ -3314,7 +3314,7 @@ class U_COMMON_API UnicodeString : public Replaceable
UnicodeString(const UnicodeString& that);
/**
- * Move constructor, might leave src in bogus state.
+ * Move constructor; might leave src in bogus state.
* This string will have the same contents and state that the source string had.
* @param src source string
* @stable ICU 56
diff --git a/deps/icu-small/source/common/unicode/urename.h b/deps/icu-small/source/common/unicode/urename.h
index d8ab85091f5721..4175e527f404a7 100644
--- a/deps/icu-small/source/common/unicode/urename.h
+++ b/deps/icu-small/source/common/unicode/urename.h
@@ -613,6 +613,7 @@
#define ucnv_createConverterFromPackage U_ICU_ENTRY_POINT_RENAME(ucnv_createConverterFromPackage)
#define ucnv_createConverterFromSharedData U_ICU_ENTRY_POINT_RENAME(ucnv_createConverterFromSharedData)
#define ucnv_detectUnicodeSignature U_ICU_ENTRY_POINT_RENAME(ucnv_detectUnicodeSignature)
+#define ucnv_enableCleanup U_ICU_ENTRY_POINT_RENAME(ucnv_enableCleanup)
#define ucnv_extContinueMatchFromU U_ICU_ENTRY_POINT_RENAME(ucnv_extContinueMatchFromU)
#define ucnv_extContinueMatchToU U_ICU_ENTRY_POINT_RENAME(ucnv_extContinueMatchToU)
#define ucnv_extGetUnicodeSet U_ICU_ENTRY_POINT_RENAME(ucnv_extGetUnicodeSet)
@@ -1170,6 +1171,16 @@
#define unum_setSymbol U_ICU_ENTRY_POINT_RENAME(unum_setSymbol)
#define unum_setTextAttribute U_ICU_ENTRY_POINT_RENAME(unum_setTextAttribute)
#define unum_toPattern U_ICU_ENTRY_POINT_RENAME(unum_toPattern)
+#define unumf_close U_ICU_ENTRY_POINT_RENAME(unumf_close)
+#define unumf_closeResult U_ICU_ENTRY_POINT_RENAME(unumf_closeResult)
+#define unumf_formatDecimal U_ICU_ENTRY_POINT_RENAME(unumf_formatDecimal)
+#define unumf_formatDouble U_ICU_ENTRY_POINT_RENAME(unumf_formatDouble)
+#define unumf_formatInt U_ICU_ENTRY_POINT_RENAME(unumf_formatInt)
+#define unumf_openForSkeletonAndLocale U_ICU_ENTRY_POINT_RENAME(unumf_openForSkeletonAndLocale)
+#define unumf_openResult U_ICU_ENTRY_POINT_RENAME(unumf_openResult)
+#define unumf_resultGetAllFieldPositions U_ICU_ENTRY_POINT_RENAME(unumf_resultGetAllFieldPositions)
+#define unumf_resultNextFieldPosition U_ICU_ENTRY_POINT_RENAME(unumf_resultNextFieldPosition)
+#define unumf_resultToString U_ICU_ENTRY_POINT_RENAME(unumf_resultToString)
#define unumsys_close U_ICU_ENTRY_POINT_RENAME(unumsys_close)
#define unumsys_getDescription U_ICU_ENTRY_POINT_RENAME(unumsys_getDescription)
#define unumsys_getName U_ICU_ENTRY_POINT_RENAME(unumsys_getName)
@@ -1209,6 +1220,7 @@
#define uplug_setPlugNoUnload U_ICU_ENTRY_POINT_RENAME(uplug_setPlugNoUnload)
#define uprops_getSource U_ICU_ENTRY_POINT_RENAME(uprops_getSource)
#define upropsvec_addPropertyStarts U_ICU_ENTRY_POINT_RENAME(upropsvec_addPropertyStarts)
+#define uprv_add32_overflow U_ICU_ENTRY_POINT_RENAME(uprv_add32_overflow)
#define uprv_aestrncpy U_ICU_ENTRY_POINT_RENAME(uprv_aestrncpy)
#define uprv_asciiFromEbcdic U_ICU_ENTRY_POINT_RENAME(uprv_asciiFromEbcdic)
#define uprv_asciitolower U_ICU_ENTRY_POINT_RENAME(uprv_asciitolower)
@@ -1343,6 +1355,7 @@
#define uprv_maximumPtr U_ICU_ENTRY_POINT_RENAME(uprv_maximumPtr)
#define uprv_min U_ICU_ENTRY_POINT_RENAME(uprv_min)
#define uprv_modf U_ICU_ENTRY_POINT_RENAME(uprv_modf)
+#define uprv_mul32_overflow U_ICU_ENTRY_POINT_RENAME(uprv_mul32_overflow)
#define uprv_parseCurrency U_ICU_ENTRY_POINT_RENAME(uprv_parseCurrency)
#define uprv_pathIsAbsolute U_ICU_ENTRY_POINT_RENAME(uprv_pathIsAbsolute)
#define uprv_pow U_ICU_ENTRY_POINT_RENAME(uprv_pow)
diff --git a/deps/icu-small/source/common/unicode/uscript.h b/deps/icu-small/source/common/unicode/uscript.h
index 0befa1cd422c20..faf9edf8ae2694 100644
--- a/deps/icu-small/source/common/unicode/uscript.h
+++ b/deps/icu-small/source/common/unicode/uscript.h
@@ -451,6 +451,21 @@ typedef enum UScriptCode {
/** @stable ICU 60 */
USCRIPT_ZANABAZAR_SQUARE = 177,/* Zanb */
+ /** @stable ICU 62 */
+ USCRIPT_DOGRA = 178,/* Dogr */
+ /** @stable ICU 62 */
+ USCRIPT_GUNJALA_GONDI = 179,/* Gong */
+ /** @stable ICU 62 */
+ USCRIPT_MAKASAR = 180,/* Maka */
+ /** @stable ICU 62 */
+ USCRIPT_MEDEFAIDRIN = 181,/* Medf */
+ /** @stable ICU 62 */
+ USCRIPT_HANIFI_ROHINGYA = 182,/* Rohg */
+ /** @stable ICU 62 */
+ USCRIPT_SOGDIAN = 183,/* Sogd */
+ /** @stable ICU 62 */
+ USCRIPT_OLD_SOGDIAN = 184,/* Sogo */
+
#ifndef U_HIDE_DEPRECATED_API
/**
* One more than the highest normal UScriptCode value.
@@ -458,7 +473,7 @@ typedef enum UScriptCode {
*
* @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420.
*/
- USCRIPT_CODE_LIMIT = 178
+ USCRIPT_CODE_LIMIT = 185
#endif // U_HIDE_DEPRECATED_API
} UScriptCode;
diff --git a/deps/icu-small/source/common/unicode/utypes.h b/deps/icu-small/source/common/unicode/utypes.h
index b6cf4965112a16..f43056b6f2fd10 100644
--- a/deps/icu-small/source/common/unicode/utypes.h
+++ b/deps/icu-small/source/common/unicode/utypes.h
@@ -542,12 +542,15 @@ typedef enum UErrorCode {
#ifndef U_HIDE_DRAFT_API
U_NUMBER_ARG_OUTOFBOUNDS_ERROR, /**< The argument to a NumberFormatter helper method was out of bounds; the bounds are usually 0 to 999. @draft ICU 61 */
#endif // U_HIDE_DRAFT_API
+#ifndef U_HIDE_DRAFT_API
+ U_NUMBER_SKELETON_SYNTAX_ERROR, /**< The number skeleton passed to C++ NumberFormatter or C UNumberFormatter was invalid or contained a syntax error. @draft ICU 62 */
+#endif // U_HIDE_DRAFT_API
#ifndef U_HIDE_DEPRECATED_API
/**
* One more than the highest normal formatting API error code.
* @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420.
*/
- U_FMT_PARSE_ERROR_LIMIT = 0x10113,
+ U_FMT_PARSE_ERROR_LIMIT = 0x10114,
#endif // U_HIDE_DEPRECATED_API
/*
diff --git a/deps/icu-small/source/common/unicode/uvernum.h b/deps/icu-small/source/common/unicode/uvernum.h
index 0427bcb03db4e3..2240661112c1ad 100644
--- a/deps/icu-small/source/common/unicode/uvernum.h
+++ b/deps/icu-small/source/common/unicode/uvernum.h
@@ -58,7 +58,7 @@
* This value will change in the subsequent releases of ICU
* @stable ICU 2.4
*/
-#define U_ICU_VERSION_MAJOR_NUM 61
+#define U_ICU_VERSION_MAJOR_NUM 62
/** The current ICU minor version as an integer.
* This value will change in the subsequent releases of ICU
@@ -84,7 +84,7 @@
* This value will change in the subsequent releases of ICU
* @stable ICU 2.6
*/
-#define U_ICU_VERSION_SUFFIX _61
+#define U_ICU_VERSION_SUFFIX _62
/**
* \def U_DEF2_ICU_ENTRY_POINT_RENAME
@@ -119,7 +119,7 @@
* This value will change in the subsequent releases of ICU
* @stable ICU 2.4
*/
-#define U_ICU_VERSION "61.1"
+#define U_ICU_VERSION "62.1"
/**
* The current ICU library major version number as a string, for library name suffixes.
@@ -132,13 +132,13 @@
*
* @stable ICU 2.6
*/
-#define U_ICU_VERSION_SHORT "61"
+#define U_ICU_VERSION_SHORT "62"
#ifndef U_HIDE_INTERNAL_API
/** Data version in ICU4C.
* @internal ICU 4.4 Internal Use Only
**/
-#define U_ICU_DATA_VERSION "61.1"
+#define U_ICU_DATA_VERSION "62.1"
#endif /* U_HIDE_INTERNAL_API */
/*===========================================================================
diff --git a/deps/icu-small/source/common/uprops.cpp b/deps/icu-small/source/common/uprops.cpp
index b76896db1b704f..21723b32aa7c8d 100644
--- a/deps/icu-small/source/common/uprops.cpp
+++ b/deps/icu-small/source/common/uprops.cpp
@@ -282,6 +282,7 @@ static const BinaryProperty binProps[UCHAR_BINARY_LIMIT]={
{ 2, U_MASK(UPROPS_2_EMOJI_COMPONENT), defaultContains },
{ 2, 0, isRegionalIndicator },
{ 1, U_MASK(UPROPS_PREPENDED_CONCATENATION_MARK), defaultContains },
+ { 2, U_MASK(UPROPS_2_EXTENDED_PICTOGRAPHIC), defaultContains },
};
U_CAPI UBool U_EXPORT2
diff --git a/deps/icu-small/source/common/uprops.h b/deps/icu-small/source/common/uprops.h
index 6f67756cd91033..2078384c3e47dd 100644
--- a/deps/icu-small/source/common/uprops.h
+++ b/deps/icu-small/source/common/uprops.h
@@ -196,8 +196,7 @@ enum {
/*
* Properties in vector word 2
* Bits
- * 31..27 http://www.unicode.org/reports/tr51/#Emoji_Properties
- * 26 reserved
+ * 31..26 http://www.unicode.org/reports/tr51/#Emoji_Properties
* 25..20 Line Break
* 19..15 Sentence Break
* 14..10 Word Break
@@ -205,7 +204,8 @@ enum {
* 4.. 0 Decomposition Type
*/
enum {
- UPROPS_2_EMOJI_COMPONENT=27,
+ UPROPS_2_EXTENDED_PICTOGRAPHIC=26,
+ UPROPS_2_EMOJI_COMPONENT,
UPROPS_2_EMOJI,
UPROPS_2_EMOJI_PRESENTATION,
UPROPS_2_EMOJI_MODIFIER,
diff --git a/deps/icu-small/source/common/uscript_props.cpp b/deps/icu-small/source/common/uscript_props.cpp
index 7998c52c7f02c5..bfdb68c7a9c998 100644
--- a/deps/icu-small/source/common/uscript_props.cpp
+++ b/deps/icu-small/source/common/uscript_props.cpp
@@ -71,7 +71,7 @@ const int32_t SCRIPT_PROPS[] = {
0x0EA5 | RECOMMENDED | LB_LETTERS, // Laoo
0x004C | RECOMMENDED | CASED, // Latn
0x0D15 | RECOMMENDED, // Mlym
- 0x1826 | LIMITED_USE, // Mong
+ 0x1826 | EXCLUSION, // Mong
0x1000 | RECOMMENDED | LB_LETTERS, // Mymr
0x168F | EXCLUSION, // Ogam
0x10300 | EXCLUSION, // Ital
@@ -222,6 +222,13 @@ const int32_t SCRIPT_PROPS[] = {
0x11D10 | EXCLUSION, // Gonm
0x11A5C | EXCLUSION, // Soyo
0x11A0B | EXCLUSION, // Zanb
+ 0x1180B | EXCLUSION, // Dogr
+ 0x11D71 | LIMITED_USE, // Gong
+ 0x11EE5 | EXCLUSION, // Maka
+ 0x16E40 | EXCLUSION | CASED, // Medf
+ 0x10D12 | LIMITED_USE | RTL, // Rohg
+ 0x10F42 | EXCLUSION | RTL, // Sogd
+ 0x10F19 | EXCLUSION | RTL, // Sogo
// End copy-paste from parsescriptmetadata.py
};
diff --git a/deps/icu-small/source/common/ustr_cnv.cpp b/deps/icu-small/source/common/ustr_cnv.cpp
index 951864f4a6c7db..eb37232c25d50b 100644
--- a/deps/icu-small/source/common/ustr_cnv.cpp
+++ b/deps/icu-small/source/common/ustr_cnv.cpp
@@ -28,6 +28,7 @@
#include "cmemory.h"
#include "umutex.h"
#include "ustr_cnv.h"
+#include "ucnv_bld.h"
/* mutexed access to a shared default converter ----------------------------- */
@@ -68,8 +69,8 @@ u_releaseDefaultConverter(UConverter *converter)
if (converter != NULL) {
ucnv_reset(converter);
}
+ ucnv_enableCleanup();
umtx_lock(NULL);
-
if(gDefaultConverter == NULL) {
gDefaultConverter = converter;
converter = NULL;
diff --git a/deps/icu-small/source/common/util.h b/deps/icu-small/source/common/util.h
index 7af9a32d8ffe53..92cdc9ef69a58a 100644
--- a/deps/icu-small/source/common/util.h
+++ b/deps/icu-small/source/common/util.h
@@ -46,6 +46,13 @@ class U_COMMON_API ICU_Utility /* not : public UObject because all methods are s
int32_t radix = 10,
int32_t minDigits = 1);
+ /** Returns a bogus UnicodeString by value. */
+ static inline UnicodeString makeBogusString() {
+ UnicodeString result;
+ result.setToBogus();
+ return result;
+ }
+
/**
* Return true if the character is NOT printable ASCII.
*
diff --git a/deps/icu-small/source/common/utypes.cpp b/deps/icu-small/source/common/utypes.cpp
index 5d6a0504ba682a..7531e465683342 100644
--- a/deps/icu-small/source/common/utypes.cpp
+++ b/deps/icu-small/source/common/utypes.cpp
@@ -126,7 +126,8 @@ _uFmtErrorName[U_FMT_PARSE_ERROR_LIMIT - U_FMT_PARSE_ERROR_START] = {
"U_DEFAULT_KEYWORD_MISSING",
"U_DECIMAL_NUMBER_SYNTAX_ERROR",
"U_FORMAT_INEXACT_ERROR",
- "U_NUMBER_ARG_OUTOFBOUNDS_ERROR"
+ "U_NUMBER_ARG_OUTOFBOUNDS_ERROR",
+ "U_NUMBER_SKELETON_SYNTAX_ERROR",
};
static const char * const
diff --git a/deps/icu-small/source/common/wintz.cpp b/deps/icu-small/source/common/wintz.cpp
index c30a5dbc606894..3708925b38f0cd 100644
--- a/deps/icu-small/source/common/wintz.cpp
+++ b/deps/icu-small/source/common/wintz.cpp
@@ -49,7 +49,7 @@ typedef struct
/**
* Various registry keys and key fragments.
*/
-static const char CURRENT_ZONE_REGKEY[] = "SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation\\";
+static const wchar_t CURRENT_ZONE_REGKEY[] = L"SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation\\";
static const char STANDARD_TIME_REGKEY[] = " Standard Time";
static const char TZI_REGKEY[] = "TZI";
static const char STD_REGKEY[] = "Std";
@@ -121,27 +121,39 @@ static LONG getSTDName(const char *winid, char *regStdName, int32_t length)
return result;
}
-static LONG getTZKeyName(char* tzKeyName, int32_t length)
+static LONG getTZKeyName(char* tzKeyName, int32_t tzKeyNamelength)
{
HKEY hkey;
LONG result = FALSE;
- DWORD cbData = length;
+ WCHAR timeZoneKeyNameData[128];
+ DWORD timeZoneKeyNameLength = static_cast(sizeof(timeZoneKeyNameData));
- if(ERROR_SUCCESS == RegOpenKeyExA(
+ if(ERROR_SUCCESS == RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
CURRENT_ZONE_REGKEY,
0,
KEY_QUERY_VALUE,
&hkey))
{
- result = RegQueryValueExA(
+ if (ERROR_SUCCESS == RegQueryValueExW(
hkey,
- "TimeZoneKeyName",
+ L"TimeZoneKeyName",
NULL,
NULL,
- (LPBYTE)tzKeyName,
- &cbData);
+ (LPBYTE)timeZoneKeyNameData,
+ &timeZoneKeyNameLength))
+ {
+ // Ensure null termination.
+ timeZoneKeyNameData[UPRV_LENGTHOF(timeZoneKeyNameData) - 1] = L'\0';
+ // Convert the UTF-16 string to UTF-8.
+ UErrorCode status = U_ZERO_ERROR;
+ u_strToUTF8(tzKeyName, tzKeyNamelength, NULL, reinterpret_cast(timeZoneKeyNameData), -1, &status);
+ if (U_ZERO_ERROR == status)
+ {
+ result = ERROR_SUCCESS;
+ }
+ }
RegCloseKey(hkey);
}
diff --git a/deps/icu-small/source/data/in/icudt61l.dat b/deps/icu-small/source/data/in/icudt62l.dat
similarity index 65%
rename from deps/icu-small/source/data/in/icudt61l.dat
rename to deps/icu-small/source/data/in/icudt62l.dat
index e9c24d8d1a7882..a6ac7ebb374980 100644
Binary files a/deps/icu-small/source/data/in/icudt61l.dat and b/deps/icu-small/source/data/in/icudt62l.dat differ
diff --git a/deps/icu-small/source/i18n/affixpatternparser.cpp b/deps/icu-small/source/i18n/affixpatternparser.cpp
deleted file mode 100644
index d9e122953af53e..00000000000000
--- a/deps/icu-small/source/i18n/affixpatternparser.cpp
+++ /dev/null
@@ -1,698 +0,0 @@
-// © 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 name: affixpatternparser.cpp
- */
-
-#include "unicode/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/dcfmtsym.h"
-#include "unicode/plurrule.h"
-#include "unicode/strenum.h"
-#include "unicode/ucurr.h"
-#include "unicode/ustring.h"
-#include "affixpatternparser.h"
-#include "charstr.h"
-#include "precision.h"
-#include "uassert.h"
-#include "unistrappender.h"
-
-static const UChar gDefaultSymbols[] = {0xa4, 0xa4, 0xa4};
-
-static const UChar gPercent = 0x25;
-static const UChar gPerMill = 0x2030;
-static const UChar gNegative = 0x2D;
-static const UChar gPositive = 0x2B;
-
-#define PACK_TOKEN_AND_LENGTH(t, l) ((UChar) (((t) << 8) | (l & 0xFF)))
-
-#define UNPACK_TOKEN(c) ((AffixPattern::ETokenType) (((c) >> 8) & 0x7F))
-
-#define UNPACK_LONG(c) (((c) >> 8) & 0x80)
-
-#define UNPACK_LENGTH(c) ((c) & 0xFF)
-
-U_NAMESPACE_BEGIN
-
-static int32_t
-nextToken(const UChar *buffer, int32_t idx, int32_t len, UChar *token) {
- if (buffer[idx] != 0x27 || idx + 1 == len) {
- *token = buffer[idx];
- return 1;
- }
- *token = buffer[idx + 1];
- if (buffer[idx + 1] == 0xA4) {
- int32_t i = 2;
- for (; idx + i < len && i < 4 && buffer[idx + i] == buffer[idx + 1]; ++i)
- ;
- return i;
- }
- return 2;
-}
-
-static int32_t
-nextUserToken(const UChar *buffer, int32_t idx, int32_t len, UChar *token) {
- *token = buffer[idx];
- int32_t max;
- switch (buffer[idx]) {
- case 0x27:
- max = 2;
- break;
- case 0xA4:
- max = 3;
- break;
- default:
- max = 1;
- break;
- }
- int32_t i = 1;
- for (; idx + i < len && i < max && buffer[idx + i] == buffer[idx]; ++i)
- ;
- return i;
-}
-
-CurrencyAffixInfo::CurrencyAffixInfo()
- : fSymbol(gDefaultSymbols, 1),
- fISO(gDefaultSymbols, 2),
- fLong(DigitAffix(gDefaultSymbols, 3)),
- fIsDefault(TRUE) {
-}
-
-void
-CurrencyAffixInfo::set(
- const char *locale,
- const PluralRules *rules,
- const UChar *currency,
- UErrorCode &status) {
- if (U_FAILURE(status)) {
- return;
- }
- fIsDefault = FALSE;
- if (currency == NULL) {
- fSymbol.setTo(gDefaultSymbols, 1);
- fISO.setTo(gDefaultSymbols, 2);
- fLong.remove();
- fLong.append(gDefaultSymbols, 3);
- fIsDefault = TRUE;
- return;
- }
- int32_t len;
- UBool unusedIsChoice;
- const UChar *symbol = ucurr_getName(
- currency, locale, UCURR_SYMBOL_NAME, &unusedIsChoice,
- &len, &status);
- if (U_FAILURE(status)) {
- return;
- }
- fSymbol.setTo(symbol, len);
- fISO.setTo(currency, u_strlen(currency));
- fLong.remove();
- StringEnumeration* keywords = rules->getKeywords(status);
- if (U_FAILURE(status)) {
- return;
- }
- const UnicodeString* pluralCount;
- while ((pluralCount = keywords->snext(status)) != NULL) {
- CharString pCount;
- pCount.appendInvariantChars(*pluralCount, status);
- const UChar *pluralName = ucurr_getPluralName(
- currency, locale, &unusedIsChoice, pCount.data(),
- &len, &status);
- fLong.setVariant(pCount.data(), UnicodeString(pluralName, len), status);
- }
- delete keywords;
-}
-
-void
-CurrencyAffixInfo::adjustPrecision(
- const UChar *currency, const UCurrencyUsage usage,
- FixedPrecision &precision, UErrorCode &status) {
- if (U_FAILURE(status)) {
- return;
- }
-
- int32_t digitCount = ucurr_getDefaultFractionDigitsForUsage(
- currency, usage, &status);
- precision.fMin.setFracDigitCount(digitCount);
- precision.fMax.setFracDigitCount(digitCount);
- double increment = ucurr_getRoundingIncrementForUsage(
- currency, usage, &status);
- if (increment == 0.0) {
- precision.fRoundingIncrement.clear();
- } else {
- precision.fRoundingIncrement.set(increment);
- // guard against round-off error
- precision.fRoundingIncrement.round(6);
- }
-}
-
-void
-AffixPattern::addLiteral(
- const UChar *literal, int32_t start, int32_t len) {
- char32Count += u_countChar32(literal + start, len);
- literals.append(literal, start, len);
- int32_t tlen = tokens.length();
- // Takes 4 UChars to encode maximum literal length.
- UChar *tokenChars = tokens.getBuffer(tlen + 4);
-
- // find start of literal size. May be tlen if there is no literal.
- // While finding start of literal size, compute literal length
- int32_t literalLength = 0;
- int32_t tLiteralStart = tlen;
- while (tLiteralStart > 0 && UNPACK_TOKEN(tokenChars[tLiteralStart - 1]) == kLiteral) {
- tLiteralStart--;
- literalLength <<= 8;
- literalLength |= UNPACK_LENGTH(tokenChars[tLiteralStart]);
- }
- // Add number of chars we just added to literal
- literalLength += len;
-
- // Now encode the new length starting at tLiteralStart
- tlen = tLiteralStart;
- tokenChars[tlen++] = PACK_TOKEN_AND_LENGTH(kLiteral, literalLength & 0xFF);
- literalLength >>= 8;
- while (literalLength) {
- tokenChars[tlen++] = PACK_TOKEN_AND_LENGTH(kLiteral | 0x80, literalLength & 0xFF);
- literalLength >>= 8;
- }
- tokens.releaseBuffer(tlen);
-}
-
-void
-AffixPattern::add(ETokenType t) {
- add(t, 1);
-}
-
-void
-AffixPattern::addCurrency(uint8_t count) {
- add(kCurrency, count);
-}
-
-void
-AffixPattern::add(ETokenType t, uint8_t count) {
- U_ASSERT(t != kLiteral);
- char32Count += count;
- switch (t) {
- case kCurrency:
- hasCurrencyToken = TRUE;
- break;
- case kPercent:
- hasPercentToken = TRUE;
- break;
- case kPerMill:
- hasPermillToken = TRUE;
- break;
- default:
- // Do nothing
- break;
- }
- tokens.append(PACK_TOKEN_AND_LENGTH(t, count));
-}
-
-AffixPattern &
-AffixPattern::append(const AffixPattern &other) {
- AffixPatternIterator iter;
- other.iterator(iter);
- UnicodeString literal;
- while (iter.nextToken()) {
- switch (iter.getTokenType()) {
- case kLiteral:
- iter.getLiteral(literal);
- addLiteral(literal.getBuffer(), 0, literal.length());
- break;
- case kCurrency:
- addCurrency(static_cast(iter.getTokenLength()));
- break;
- default:
- add(iter.getTokenType());
- break;
- }
- }
- return *this;
-}
-
-void
-AffixPattern::remove() {
- tokens.remove();
- literals.remove();
- hasCurrencyToken = FALSE;
- hasPercentToken = FALSE;
- hasPermillToken = FALSE;
- char32Count = 0;
-}
-
-// escapes literals for strings where special characters are NOT escaped
-// except for apostrophe.
-static void escapeApostropheInLiteral(
- const UnicodeString &literal, UnicodeStringAppender &appender) {
- int32_t len = literal.length();
- const UChar *buffer = literal.getBuffer();
- for (int32_t i = 0; i < len; ++i) {
- UChar ch = buffer[i];
- switch (ch) {
- case 0x27:
- appender.append((UChar) 0x27);
- appender.append((UChar) 0x27);
- break;
- default:
- appender.append(ch);
- break;
- }
- }
-}
-
-
-// escapes literals for user strings where special characters in literals
-// are escaped with apostrophe.
-static void escapeLiteral(
- const UnicodeString &literal, UnicodeStringAppender &appender) {
- int32_t len = literal.length();
- const UChar *buffer = literal.getBuffer();
- for (int32_t i = 0; i < len; ++i) {
- UChar ch = buffer[i];
- switch (ch) {
- case 0x27:
- appender.append((UChar) 0x27);
- appender.append((UChar) 0x27);
- break;
- case 0x25:
- appender.append((UChar) 0x27);
- appender.append((UChar) 0x25);
- appender.append((UChar) 0x27);
- break;
- case 0x2030:
- appender.append((UChar) 0x27);
- appender.append((UChar) 0x2030);
- appender.append((UChar) 0x27);
- break;
- case 0xA4:
- appender.append((UChar) 0x27);
- appender.append((UChar) 0xA4);
- appender.append((UChar) 0x27);
- break;
- case 0x2D:
- appender.append((UChar) 0x27);
- appender.append((UChar) 0x2D);
- appender.append((UChar) 0x27);
- break;
- case 0x2B:
- appender.append((UChar) 0x27);
- appender.append((UChar) 0x2B);
- appender.append((UChar) 0x27);
- break;
- default:
- appender.append(ch);
- break;
- }
- }
-}
-
-UnicodeString &
-AffixPattern::toString(UnicodeString &appendTo) const {
- AffixPatternIterator iter;
- iterator(iter);
- UnicodeStringAppender appender(appendTo);
- UnicodeString literal;
- while (iter.nextToken()) {
- switch (iter.getTokenType()) {
- case kLiteral:
- escapeApostropheInLiteral(iter.getLiteral(literal), appender);
- break;
- case kPercent:
- appender.append((UChar) 0x27);
- appender.append((UChar) 0x25);
- break;
- case kPerMill:
- appender.append((UChar) 0x27);
- appender.append((UChar) 0x2030);
- break;
- case kCurrency:
- {
- appender.append((UChar) 0x27);
- int32_t cl = iter.getTokenLength();
- for (int32_t i = 0; i < cl; ++i) {
- appender.append((UChar) 0xA4);
- }
- }
- break;
- case kNegative:
- appender.append((UChar) 0x27);
- appender.append((UChar) 0x2D);
- break;
- case kPositive:
- appender.append((UChar) 0x27);
- appender.append((UChar) 0x2B);
- break;
- default:
- U_ASSERT(FALSE);
- break;
- }
- }
- return appendTo;
-}
-
-UnicodeString &
-AffixPattern::toUserString(UnicodeString &appendTo) const {
- AffixPatternIterator iter;
- iterator(iter);
- UnicodeStringAppender appender(appendTo);
- UnicodeString literal;
- while (iter.nextToken()) {
- switch (iter.getTokenType()) {
- case kLiteral:
- escapeLiteral(iter.getLiteral(literal), appender);
- break;
- case kPercent:
- appender.append((UChar) 0x25);
- break;
- case kPerMill:
- appender.append((UChar) 0x2030);
- break;
- case kCurrency:
- {
- int32_t cl = iter.getTokenLength();
- for (int32_t i = 0; i < cl; ++i) {
- appender.append((UChar) 0xA4);
- }
- }
- break;
- case kNegative:
- appender.append((UChar) 0x2D);
- break;
- case kPositive:
- appender.append((UChar) 0x2B);
- break;
- default:
- U_ASSERT(FALSE);
- break;
- }
- }
- return appendTo;
-}
-
-class AffixPatternAppender : public UMemory {
-public:
- AffixPatternAppender(AffixPattern &dest) : fDest(&dest), fIdx(0) { }
-
- inline void append(UChar x) {
- if (fIdx == UPRV_LENGTHOF(fBuffer)) {
- fDest->addLiteral(fBuffer, 0, fIdx);
- fIdx = 0;
- }
- fBuffer[fIdx++] = x;
- }
-
- inline void append(UChar32 x) {
- if (fIdx >= UPRV_LENGTHOF(fBuffer) - 1) {
- fDest->addLiteral(fBuffer, 0, fIdx);
- fIdx = 0;
- }
- U16_APPEND_UNSAFE(fBuffer, fIdx, x);
- }
-
- inline void flush() {
- if (fIdx) {
- fDest->addLiteral(fBuffer, 0, fIdx);
- }
- fIdx = 0;
- }
-
- /**
- * flush the buffer when we go out of scope.
- */
- ~AffixPatternAppender() {
- flush();
- }
-private:
- AffixPattern *fDest;
- int32_t fIdx;
- UChar fBuffer[32];
- AffixPatternAppender(const AffixPatternAppender &other);
- AffixPatternAppender &operator=(const AffixPatternAppender &other);
-};
-
-
-AffixPattern &
-AffixPattern::parseUserAffixString(
- const UnicodeString &affixStr,
- AffixPattern &appendTo,
- UErrorCode &status) {
- if (U_FAILURE(status)) {
- return appendTo;
- }
- int32_t len = affixStr.length();
- const UChar *buffer = affixStr.getBuffer();
- // 0 = not quoted; 1 = quoted.
- int32_t state = 0;
- AffixPatternAppender appender(appendTo);
- for (int32_t i = 0; i < len; ) {
- UChar token;
- int32_t tokenSize = nextUserToken(buffer, i, len, &token);
- i += tokenSize;
- if (token == 0x27 && tokenSize == 1) { // quote
- state = 1 - state;
- continue;
- }
- if (state == 0) {
- switch (token) {
- case 0x25:
- appender.flush();
- appendTo.add(kPercent, 1);
- break;
- case 0x27: // double quote
- appender.append((UChar) 0x27);
- break;
- case 0x2030:
- appender.flush();
- appendTo.add(kPerMill, 1);
- break;
- case 0x2D:
- appender.flush();
- appendTo.add(kNegative, 1);
- break;
- case 0x2B:
- appender.flush();
- appendTo.add(kPositive, 1);
- break;
- case 0xA4:
- appender.flush();
- appendTo.add(kCurrency, static_cast(tokenSize));
- break;
- default:
- appender.append(token);
- break;
- }
- } else {
- switch (token) {
- case 0x27: // double quote
- appender.append((UChar) 0x27);
- break;
- case 0xA4: // included b/c tokenSize can be > 1
- for (int32_t j = 0; j < tokenSize; ++j) {
- appender.append((UChar) 0xA4);
- }
- break;
- default:
- appender.append(token);
- break;
- }
- }
- }
- return appendTo;
-}
-
-AffixPattern &
-AffixPattern::parseAffixString(
- const UnicodeString &affixStr,
- AffixPattern &appendTo,
- UErrorCode &status) {
- if (U_FAILURE(status)) {
- return appendTo;
- }
- int32_t len = affixStr.length();
- const UChar *buffer = affixStr.getBuffer();
- for (int32_t i = 0; i < len; ) {
- UChar token;
- int32_t tokenSize = nextToken(buffer, i, len, &token);
- if (tokenSize == 1) {
- int32_t literalStart = i;
- ++i;
- while (i < len && (tokenSize = nextToken(buffer, i, len, &token)) == 1) {
- ++i;
- }
- appendTo.addLiteral(buffer, literalStart, i - literalStart);
-
- // If we reached end of string, we are done
- if (i == len) {
- return appendTo;
- }
- }
- i += tokenSize;
- switch (token) {
- case 0x25:
- appendTo.add(kPercent, 1);
- break;
- case 0x2030:
- appendTo.add(kPerMill, 1);
- break;
- case 0x2D:
- appendTo.add(kNegative, 1);
- break;
- case 0x2B:
- appendTo.add(kPositive, 1);
- break;
- case 0xA4:
- {
- if (tokenSize - 1 > 3) {
- status = U_PARSE_ERROR;
- return appendTo;
- }
- appendTo.add(kCurrency, tokenSize - 1);
- }
- break;
- default:
- appendTo.addLiteral(&token, 0, 1);
- break;
- }
- }
- return appendTo;
-}
-
-AffixPatternIterator &
-AffixPattern::iterator(AffixPatternIterator &result) const {
- result.nextLiteralIndex = 0;
- result.lastLiteralLength = 0;
- result.nextTokenIndex = 0;
- result.tokens = &tokens;
- result.literals = &literals;
- return result;
-}
-
-UBool
-AffixPatternIterator::nextToken() {
- int32_t tlen = tokens->length();
- if (nextTokenIndex == tlen) {
- return FALSE;
- }
- ++nextTokenIndex;
- const UChar *tokenBuffer = tokens->getBuffer();
- if (UNPACK_TOKEN(tokenBuffer[nextTokenIndex - 1]) ==
- AffixPattern::kLiteral) {
- while (nextTokenIndex < tlen &&
- UNPACK_LONG(tokenBuffer[nextTokenIndex])) {
- ++nextTokenIndex;
- }
- lastLiteralLength = 0;
- int32_t i = nextTokenIndex - 1;
- for (; UNPACK_LONG(tokenBuffer[i]); --i) {
- lastLiteralLength <<= 8;
- lastLiteralLength |= UNPACK_LENGTH(tokenBuffer[i]);
- }
- lastLiteralLength <<= 8;
- lastLiteralLength |= UNPACK_LENGTH(tokenBuffer[i]);
- nextLiteralIndex += lastLiteralLength;
- }
- return TRUE;
-}
-
-AffixPattern::ETokenType
-AffixPatternIterator::getTokenType() const {
- return UNPACK_TOKEN(tokens->charAt(nextTokenIndex - 1));
-}
-
-UnicodeString &
-AffixPatternIterator::getLiteral(UnicodeString &result) const {
- const UChar *buffer = literals->getBuffer();
- result.setTo(buffer + (nextLiteralIndex - lastLiteralLength), lastLiteralLength);
- return result;
-}
-
-int32_t
-AffixPatternIterator::getTokenLength() const {
- const UChar *tokenBuffer = tokens->getBuffer();
- AffixPattern::ETokenType type = UNPACK_TOKEN(tokenBuffer[nextTokenIndex - 1]);
- return type == AffixPattern::kLiteral ? lastLiteralLength : UNPACK_LENGTH(tokenBuffer[nextTokenIndex - 1]);
-}
-
-AffixPatternParser::AffixPatternParser()
- : fPercent(gPercent), fPermill(gPerMill), fNegative(gNegative), fPositive(gPositive) {
-}
-
-AffixPatternParser::AffixPatternParser(
- const DecimalFormatSymbols &symbols) {
- setDecimalFormatSymbols(symbols);
-}
-
-void
-AffixPatternParser::setDecimalFormatSymbols(
- const DecimalFormatSymbols &symbols) {
- fPercent = symbols.getConstSymbol(DecimalFormatSymbols::kPercentSymbol);
- fPermill = symbols.getConstSymbol(DecimalFormatSymbols::kPerMillSymbol);
- fNegative = symbols.getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
- fPositive = symbols.getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
-}
-
-PluralAffix &
-AffixPatternParser::parse(
- const AffixPattern &affixPattern,
- const CurrencyAffixInfo ¤cyAffixInfo,
- PluralAffix &appendTo,
- UErrorCode &status) const {
- if (U_FAILURE(status)) {
- return appendTo;
- }
- AffixPatternIterator iter;
- affixPattern.iterator(iter);
- UnicodeString literal;
- while (iter.nextToken()) {
- switch (iter.getTokenType()) {
- case AffixPattern::kPercent:
- appendTo.append(fPercent, UNUM_PERCENT_FIELD);
- break;
- case AffixPattern::kPerMill:
- appendTo.append(fPermill, UNUM_PERMILL_FIELD);
- break;
- case AffixPattern::kNegative:
- appendTo.append(fNegative, UNUM_SIGN_FIELD);
- break;
- case AffixPattern::kPositive:
- appendTo.append(fPositive, UNUM_SIGN_FIELD);
- break;
- case AffixPattern::kCurrency:
- switch (iter.getTokenLength()) {
- case 1:
- appendTo.append(
- currencyAffixInfo.getSymbol(), UNUM_CURRENCY_FIELD);
- break;
- case 2:
- appendTo.append(
- currencyAffixInfo.getISO(), UNUM_CURRENCY_FIELD);
- break;
- case 3:
- appendTo.append(
- currencyAffixInfo.getLong(), UNUM_CURRENCY_FIELD, status);
- break;
- default:
- U_ASSERT(FALSE);
- break;
- }
- break;
- case AffixPattern::kLiteral:
- appendTo.append(iter.getLiteral(literal));
- break;
- default:
- U_ASSERT(FALSE);
- break;
- }
- }
- return appendTo;
-}
-
-
-U_NAMESPACE_END
-#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/deps/icu-small/source/i18n/affixpatternparser.h b/deps/icu-small/source/i18n/affixpatternparser.h
deleted file mode 100644
index b54c749c700816..00000000000000
--- a/deps/icu-small/source/i18n/affixpatternparser.h
+++ /dev/null
@@ -1,402 +0,0 @@
-// © 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.
-*******************************************************************************
-* affixpatternparser.h
-*
-* created on: 2015jan06
-* created by: Travis Keep
-*/
-
-#ifndef __AFFIX_PATTERN_PARSER_H__
-#define __AFFIX_PATTERN_PARSER_H__
-
-#include "unicode/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/unistr.h"
-#include "unicode/uobject.h"
-#include "pluralaffix.h"
-
-U_NAMESPACE_BEGIN
-
-class PluralRules;
-class FixedPrecision;
-class DecimalFormatSymbols;
-
-/**
- * A representation of the various forms of a particular currency according
- * to some locale and usage context.
- *
- * Includes the symbol, ISO code form, and long form(s) of the currency name
- * for each plural variation.
- */
-class U_I18N_API CurrencyAffixInfo : public UMemory {
-public:
- /**
- * Symbol is \u00a4; ISO form is \u00a4\u00a4;
- * long form is \u00a4\u00a4\u00a4.
- */
- CurrencyAffixInfo();
-
- const UnicodeString &getSymbol() const { return fSymbol; }
- const UnicodeString &getISO() const { return fISO; }
- const PluralAffix &getLong() const { return fLong; }
- void setSymbol(const UnicodeString &symbol) {
- fSymbol = symbol;
- fIsDefault = FALSE;
- }
- void setISO(const UnicodeString &iso) {
- fISO = iso;
- fIsDefault = FALSE;
- }
- UBool
- equals(const CurrencyAffixInfo &other) const {
- return (fSymbol == other.fSymbol)
- && (fISO == other.fISO)
- && (fLong.equals(other.fLong))
- && (fIsDefault == other.fIsDefault);
- }
-
- /**
- * Intializes this instance.
- *
- * @param locale the locale for the currency forms.
- * @param rules The plural rules for the locale.
- * @param currency the null terminated, 3 character ISO code of the
- * currency. If NULL, resets this instance as if it were just created.
- * In this case, the first 2 parameters may be NULL as well.
- * @param status any error returned here.
- */
- void set(
- const char *locale, const PluralRules *rules,
- const UChar *currency, UErrorCode &status);
-
- /**
- * Returns true if this instance is the default. That is has no real
- * currency. For instance never initialized with set()
- * or reset with set(NULL, NULL, NULL, status).
- */
- UBool isDefault() const { return fIsDefault; }
-
- /**
- * Adjusts the precision used for a particular currency.
- * @param currency the null terminated, 3 character ISO code of the
- * currency.
- * @param usage the usage of the currency
- * @param precision min/max fraction digits and rounding increment
- * adjusted.
- * @params status any error reported here.
- */
- static void adjustPrecision(
- const UChar *currency, const UCurrencyUsage usage,
- FixedPrecision &precision, UErrorCode &status);
-
-private:
- /**
- * The symbol form of the currency.
- */
- UnicodeString fSymbol;
-
- /**
- * The ISO form of the currency, usually three letter abbreviation.
- */
- UnicodeString fISO;
-
- /**
- * The long forms of the currency keyed by plural variation.
- */
- PluralAffix fLong;
-
- UBool fIsDefault;
-
-};
-
-class AffixPatternIterator;
-
-/**
- * A locale agnostic representation of an affix pattern.
- */
-class U_I18N_API AffixPattern : public UMemory {
-public:
-
- /**
- * The token types that can appear in an affix pattern.
- */
- enum ETokenType {
- kLiteral,
- kPercent,
- kPerMill,
- kCurrency,
- kNegative,
- kPositive
- };
-
- /**
- * An empty affix pattern.
- */
- AffixPattern()
- : tokens(), literals(), hasCurrencyToken(FALSE),
- hasPercentToken(FALSE), hasPermillToken(FALSE), char32Count(0) {
- }
-
- /**
- * Adds a string literal to this affix pattern.
- */
- void addLiteral(const UChar *, int32_t start, int32_t len);
-
- /**
- * Adds a token to this affix pattern. t must not be kLiteral as
- * the addLiteral() method adds literals.
- * @param t the token type to add
- */
- void add(ETokenType t);
-
- /**
- * Adds a currency token with specific count to this affix pattern.
- * @param count the token count. Used to distinguish between
- * one, two, or three currency symbols. Note that adding a currency
- * token with count=2 (Use ISO code) is different than adding two
- * currency tokens each with count=1 (two currency symbols).
- */
- void addCurrency(uint8_t count);
-
- /**
- * Makes this instance be an empty affix pattern.
- */
- void remove();
-
- /**
- * Provides an iterator over the tokens in this instance.
- * @param result this is initialized to point just before the
- * first token of this instance. Caller must call nextToken()
- * on the iterator once it is set up to have it actually point
- * to the first token. This first call to nextToken() will return
- * FALSE if the AffixPattern being iterated over is empty.
- * @return result
- */
- AffixPatternIterator &iterator(AffixPatternIterator &result) const;
-
- /**
- * Returns TRUE if this instance has currency tokens in it.
- */
- UBool usesCurrency() const {
- return hasCurrencyToken;
- }
-
- UBool usesPercent() const {
- return hasPercentToken;
- }
-
- UBool usesPermill() const {
- return hasPermillToken;
- }
-
- /**
- * Returns the number of code points a string of this instance
- * would have if none of the special tokens were escaped.
- * Used to compute the padding size.
- */
- int32_t countChar32() const {
- return char32Count;
- }
-
- /**
- * Appends other to this instance mutating this instance in place.
- * @param other The pattern appended to the end of this one.
- * @return a reference to this instance for chaining.
- */
- AffixPattern &append(const AffixPattern &other);
-
- /**
- * Converts this AffixPattern back into a user string.
- * It is the inverse of parseUserAffixString.
- */
- UnicodeString &toUserString(UnicodeString &appendTo) const;
-
- /**
- * Converts this AffixPattern back into a string.
- * It is the inverse of parseAffixString.
- */
- UnicodeString &toString(UnicodeString &appendTo) const;
-
- /**
- * Parses an affix pattern string appending it to an AffixPattern.
- * Parses affix pattern strings produced from using
- * DecimalFormatPatternParser to parse a format pattern. Affix patterns
- * include the positive prefix and suffix and the negative prefix
- * and suffix. This method expects affix patterns strings to be in the
- * same format that DecimalFormatPatternParser produces. Namely special
- * characters in the affix that correspond to a field type must be
- * prefixed with an apostrophe ('). These special character sequences
- * inluce minus (-), percent (%), permile (U+2030), plus (+),
- * short currency (U+00a4), medium currency (u+00a4 * 2),
- * long currency (u+a4 * 3), and apostrophe (')
- * (apostrophe does not correspond to a field type but has to be escaped
- * because it itself is the escape character).
- * Since the expansion of these special character
- * sequences is locale dependent, these sequences are not expanded in
- * an AffixPattern instance.
- * If these special characters are not prefixed with an apostrophe in
- * the affix pattern string, then they are treated verbatim just as
- * any other character. If an apostrophe prefixes a non special
- * character in the affix pattern, the apostrophe is simply ignored.
- *
- * @param affixStr the string from DecimalFormatPatternParser
- * @param appendTo parsed result appended here.
- * @param status any error parsing returned here.
- */
- static AffixPattern &parseAffixString(
- const UnicodeString &affixStr,
- AffixPattern &appendTo,
- UErrorCode &status);
-
- /**
- * Parses an affix pattern string appending it to an AffixPattern.
- * Parses affix pattern strings as the user would supply them.
- * In this function, quoting makes special characters like normal
- * characters whereas in parseAffixString, quoting makes special
- * characters special.
- *
- * @param affixStr the string from the user
- * @param appendTo parsed result appended here.
- * @param status any error parsing returned here.
- */
- static AffixPattern &parseUserAffixString(
- const UnicodeString &affixStr,
- AffixPattern &appendTo,
- UErrorCode &status);
-
- UBool equals(const AffixPattern &other) const {
- return (tokens == other.tokens)
- && (literals == other.literals)
- && (hasCurrencyToken == other.hasCurrencyToken)
- && (hasPercentToken == other.hasPercentToken)
- && (hasPermillToken == other.hasPermillToken)
- && (char32Count == other.char32Count);
- }
-
-private:
- /*
- * Tokens stored here. Each UChar generally stands for one token. A
- * Each token is of form 'etttttttllllllll' llllllll is the length of
- * the token and ranges from 0-255. ttttttt is the token type and ranges
- * from 0-127. If e is set it means this is an extendo token (to be
- * described later). To accomodate token lengths above 255, each normal
- * token (e=0) can be followed by 0 or more extendo tokens (e=1) with
- * the same type. Right now only kLiteral Tokens have extendo tokens.
- * Each extendo token provides the next 8 higher bits for the length.
- * If a kLiteral token is followed by 2 extendo tokens then, then the
- * llllllll of the next extendo token contains bits 8-15 of the length
- * and the last extendo token contains bits 16-23 of the length.
- */
- UnicodeString tokens;
-
- /*
- * The characters of the kLiteral tokens are concatenated together here.
- * The first characters go with the first kLiteral token, the next
- * characters go with the next kLiteral token etc.
- */
- UnicodeString literals;
- UBool hasCurrencyToken;
- UBool hasPercentToken;
- UBool hasPermillToken;
- int32_t char32Count;
- void add(ETokenType t, uint8_t count);
-
-};
-
-/**
- * An iterator over the tokens in an AffixPattern instance.
- */
-class U_I18N_API AffixPatternIterator : public UMemory {
-public:
-
- /**
- * Using an iterator without first calling iterator on an AffixPattern
- * instance to initialize the iterator results in
- * undefined behavior.
- */
- AffixPatternIterator() : nextLiteralIndex(0), lastLiteralLength(0), nextTokenIndex(0), tokens(NULL), literals(NULL) { }
- /**
- * Advances this iterator to the next token. Returns FALSE when there
- * are no more tokens. Calling the other methods after nextToken()
- * returns FALSE results in undefined behavior.
- */
- UBool nextToken();
-
- /**
- * Returns the type of token.
- */
- AffixPattern::ETokenType getTokenType() const;
-
- /**
- * For literal tokens, returns the literal string. Calling this for
- * other token types results in undefined behavior.
- * @param result replaced with a read-only alias to the literal string.
- * @return result
- */
- UnicodeString &getLiteral(UnicodeString &result) const;
-
- /**
- * Returns the token length. Usually 1, but for currency tokens may
- * be 2 for ISO code and 3 for long form.
- */
- int32_t getTokenLength() const;
-private:
- int32_t nextLiteralIndex;
- int32_t lastLiteralLength;
- int32_t nextTokenIndex;
- const UnicodeString *tokens;
- const UnicodeString *literals;
- friend class AffixPattern;
- AffixPatternIterator(const AffixPatternIterator &);
- AffixPatternIterator &operator=(const AffixPatternIterator &);
-};
-
-/**
- * A locale aware class that converts locale independent AffixPattern
- * instances into locale dependent PluralAffix instances.
- */
-class U_I18N_API AffixPatternParser : public UMemory {
-public:
-AffixPatternParser();
-AffixPatternParser(const DecimalFormatSymbols &symbols);
-void setDecimalFormatSymbols(const DecimalFormatSymbols &symbols);
-
-/**
- * Parses affixPattern appending the result to appendTo.
- * @param affixPattern The affix pattern.
- * @param currencyAffixInfo contains the currency forms.
- * @param appendTo The result of parsing affixPattern is appended here.
- * @param status any error returned here.
- * @return appendTo.
- */
-PluralAffix &parse(
- const AffixPattern &affixPattern,
- const CurrencyAffixInfo ¤cyAffixInfo,
- PluralAffix &appendTo,
- UErrorCode &status) const;
-
-UBool equals(const AffixPatternParser &other) const {
- return (fPercent == other.fPercent)
- && (fPermill == other.fPermill)
- && (fNegative == other.fNegative)
- && (fPositive == other.fPositive);
-}
-
-private:
-UnicodeString fPercent;
-UnicodeString fPermill;
-UnicodeString fNegative;
-UnicodeString fPositive;
-};
-
-
-U_NAMESPACE_END
-#endif /* #if !UCONFIG_NO_FORMATTING */
-#endif // __AFFIX_PATTERN_PARSER_H__
diff --git a/deps/icu-small/source/i18n/collationfcd.cpp b/deps/icu-small/source/i18n/collationfcd.cpp
index 19841ee6487ad2..1aff936dee1d2a 100644
--- a/deps/icu-small/source/i18n/collationfcd.cpp
+++ b/deps/icu-small/source/i18n/collationfcd.cpp
@@ -22,27 +22,27 @@ const uint8_t CollationFCD::lcccIndex[2048]={
0,0,0,0,0,0,0,0,1,1,2,3,0,0,0,0,
0,0,0,0,4,0,0,0,0,0,0,0,5,6,7,0,
8,0,9,0xa,0,0,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0x10,
-0x11,0x12,0x13,0,0,0,0x14,0x15,0,0x16,0x17,0,0,0x16,0x18,0,
+0x11,0x12,0x13,0,0,0,0x14,0x15,0,0x16,0x17,0,0,0x16,0x18,0x19,
0,0x16,0x18,0,0,0x16,0x18,0,0,0x16,0x18,0,0,0,0x18,0,
-0,0,0x19,0,0,0x16,0x18,0,0,0x1a,0x18,0,0,0,0x1b,0,
-0,0x1c,0x1d,0,0,0x1e,0x1d,0,0x1e,0x1f,0,0x20,0x21,0,0x22,0,
-0,0x23,0,0,0x18,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0x24,0,0,0,0,0,
+0,0,0x1a,0,0,0x16,0x18,0,0,0x1b,0x18,0,0,0,0x1c,0,
+0,0x1d,0x1e,0,0,0x1f,0x1e,0,0x1f,0x20,0,0x21,0x22,0,0x23,0,
+0,0x24,0,0,0x18,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0x25,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0x25,0x25,0,0,0,0,0x26,0,
-0,0,0,0,0,0x27,0,0,0,0x13,0,0,0,0,0,0,
-0x28,0,0,0x29,0,0x2a,0,0,0,0x25,0x2b,0x10,0,0x2c,0,0x2d,
-0,0x2e,0,0,0,0,0x2f,0x30,0,0,0,0,0,0,1,0x31,
+0,0,0,0,0,0,0,0,0x26,0x26,0,0,0,0,0x27,0,
+0,0,0,0,0,0x28,0,0,0,0x13,0,0,0,0,0,0,
+0x29,0,0,0x2a,0,0x2b,0,0,0,0x26,0x2c,0x2d,0,0x2e,0,0x2f,
+0,0x30,0,0,0,0,0x31,0x32,0,0,0,0,0,0,1,0x33,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0x32,0x33,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x34,0x35,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0x34,0,0,0,0x35,0,0,0,1,
+0,0,0,0,0,0,0,0x36,0,0,0,0x37,0,0,0,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0x36,0,0,0x37,0,0,0,0,0,0,0,0,0,0,0,
+0,0x38,0,0,0x39,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
@@ -101,9 +101,9 @@ const uint8_t CollationFCD::lcccIndex[2048]={
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0x38,0x39,0,0,0x3a,0,0,0,0,0,0,0,0,
-0x22,0,0,0,0,0,0x2b,0x3b,0,0x3c,0x3d,0,0,0x3d,0x3e,0,
-0,0,0,0,0,0x3f,0x40,0x41,0,0,0,0,0,0,0,0x18,
+0,0,0,0x3a,0x3b,0,0,0x3c,0,0,0,0,0,0,0,0,
+0x23,0,0,0,0,0,0x2c,0x3d,0,0x3e,0x3f,0,0,0x3f,0x40,0,
+0,0,0,0,0,0x41,0x42,0x43,0,0,0,0,0,0,0,0x18,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
@@ -126,7 +126,7 @@ const uint8_t CollationFCD::lcccIndex[2048]={
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0x42,0x43,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x44,0x45,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
@@ -143,17 +143,17 @@ const uint8_t CollationFCD::lcccIndex[2048]={
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0x44,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x19,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
-const uint32_t CollationFCD::lcccBits[69]={
+const uint32_t CollationFCD::lcccBits[70]={
0,0xffffffff,0xffff7fff,0xffff,0xf8,0xfffe0000,0xbfffffff,0xb6,0x7ff0000,0xfffff800,0x10000,0x9fc00000,0x3d9f,0x20000,0xffff0000,0x7ff,
-0xff800,0xfbc00000,0x3eef,0xe000000,0xfff00000,0xfffffffb,0x10000000,0x1e2000,0x2000,0x602000,0x18000000,0x400,0x7000000,0xf00,0x3000000,0x2a00000,
-0x3c3e0000,0xdf,0x40,0x6800000,0xe0000000,0x100000,0x20040000,0x200,0x1800000,0x9fe00001,0x3fff0000,0x10,0xc00,0xc0040,0x800000,0xfff70000,
-0x31021fd,0xfbffffff,0x1fff0000,0x1ffe2,0x38000,0x80000000,0xfc00,0x6000000,0x3ff08000,0xc0000000,0x30000,0x3ffff,0x3800,0x80000,1,0xc19d0000,
-2,0x400000,0x40000f5,0x5108000,0x40000000
+0x200ff800,0xfbc00000,0x3eef,0xe000000,0xfff80000,0xfffffffb,0x10000000,0x1e2000,0x2000,0x40000000,0x602000,0x18000000,0x400,0x7000000,0xf00,0x3000000,
+0x2a00000,0x3c3e0000,0xdf,0x40,0x6800000,0xe0000000,0x100000,0x20040000,0x200,0x1800000,0x9fe00001,0x3fff0000,0x10,0xff800,0xc00,0xc0040,
+0x800000,0xfff70000,0x31021fd,0xfbffffff,0x1fff0000,0x1ffe2,0x38000,0x80000000,0xfc00,0x6000000,0x3ff08000,0xc0000000,0x30000,0x3ffff,0x3800,0x80000,
+1,0xc19d0000,2,0x400000,0x40000fd,0x5108000
};
const uint8_t CollationFCD::tcccIndex[2048]={
@@ -161,27 +161,27 @@ const uint8_t CollationFCD::tcccIndex[2048]={
0xb,0xc,0,0,0,0,0,0,1,1,0xd,0xe,0xf,0x10,0x11,0,
0x12,0x13,0x14,0x15,0x16,0,0x17,0x18,0,0,0,0,0x19,0x1a,0x1b,0,
0x1c,0x1d,0x1e,0x1f,0,0,0x20,0x21,0x22,0x23,0x24,0,0,0,0,0x25,
-0x26,0x27,0x28,0,0,0,0x29,0x2a,0,0x2b,0x2c,0,0,0x2d,0x2e,0,
-0,0x2f,0x30,0,0,0x2d,0x31,0,0,0x2d,0x32,0,0,0,0x31,0,
-0,0,0x33,0,0,0x2d,0x31,0,0,0x34,0x31,0,0,0,0x35,0,
-0,0x36,0x37,0,0,0x38,0x37,0,0x38,0x39,0,0x3a,0x3b,0,0x3c,0,
-0,0x3d,0,0,0x31,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0x3e,0,0,0,0,0,
+0x26,0x27,0x28,0,0,0,0x29,0x2a,0,0x2b,0x2c,0,0,0x2d,0x2e,0x2f,
+0,0x30,0x31,0,0,0x2d,0x32,0,0,0x2d,0x33,0,0,0,0x32,0,
+0,0,0x34,0,0,0x2d,0x32,0,0,0x35,0x32,0,0,0,0x36,0,
+0,0x37,0x38,0,0,0x39,0x38,0,0x39,0x3a,0,0x3b,0x3c,0,0x3d,0,
+0,0x3e,0,0,0x32,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0x3f,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0x3f,0x3f,0,0,0,0,0x40,0,
-0,0,0,0,0,0x41,0,0,0,0x28,0,0,0,0,0,0,
-0x42,0,0,0x43,0,0x44,0,0,0,0x3f,0x45,0x25,0,0x46,0,0x47,
-0,0x48,0,0,0,0,0x49,0x4a,0,0,0,0,0,0,1,0x4b,
-1,1,1,1,0x4c,1,1,0x4d,0x4e,1,0x4f,0x50,1,0x51,0x52,0x53,
-0,0,0,0,0,0,0x54,0x55,0,0x56,0,0,0x57,0x58,0x59,0,
-0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,0,0x60,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x40,0x40,0,0,0,0,0x41,0,
+0,0,0,0,0,0x42,0,0,0,0x28,0,0,0,0,0,0,
+0x43,0,0,0x44,0,0x45,0,0,0,0x40,0x46,0x47,0,0x48,0,0x49,
+0,0x4a,0,0,0,0,0x4b,0x4c,0,0,0,0,0,0,1,0x4d,
+1,1,1,1,0x4e,1,1,0x4f,0x50,1,0x51,0x52,1,0x53,0x54,0x55,
+0,0,0,0,0,0,0x56,0x57,0,0x58,0,0,0x59,0x5a,0x5b,0,
+0x5c,0x5d,0x5e,0x5f,0x60,0x61,0,0x62,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0x2d,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0x61,0,0,0,0x62,0,0,0,1,
+0,0,0,0,0,0,0,0x63,0,0,0,0x64,0,0,0,1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0x63,0x64,0x65,0x66,0x64,0x65,0x67,0,0,0,0,0,0,0,0,
+0,0x65,0x66,0x67,0x68,0x66,0x67,0x69,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
@@ -240,9 +240,9 @@ const uint8_t CollationFCD::tcccIndex[2048]={
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0x68,0x69,0,0,0x6a,0,0,0,0,0,0,0,0,
-0x3c,0,0,0,0,0,0x45,0x6b,0,0x6c,0x6d,0,0,0x6d,0x6e,0,
-0,0,0,0,0,0x6f,0x70,0x71,0,0,0,0,0,0,0,0x31,
+0,0,0,0x6a,0x6b,0,0,0x6c,0,0,0,0,0,0,0,0,
+0x3d,0,0,0,0,0,0x46,0x6d,0,0x6e,0x6f,0,0,0x6f,0x70,0,
+0,0,0,0,0,0x71,0x72,0x73,0,0,0,0,0,0,0,0x32,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
@@ -265,7 +265,7 @@ const uint8_t CollationFCD::tcccIndex[2048]={
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0x72,0x73,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x74,0x75,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
@@ -282,20 +282,20 @@ const uint8_t CollationFCD::tcccIndex[2048]={
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0x3e,0x74,0x75,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x3f,0x76,0x77,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0xe,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
-const uint32_t CollationFCD::tcccBits[118]={
+const uint32_t CollationFCD::tcccBits[120]={
0,0xffffffff,0x3e7effbf,0xbe7effbf,0xfffcffff,0x7ef1ff3f,0xfff3f1f8,0x7fffff3f,0x18003,0xdfffe000,0xff31ffcf,0xcfffffff,0xfffc0,0xffff7fff,0xffff,0x1d760,
0x1fc00,0x187c00,0x200708b,0x2000000,0x708b0000,0xc00000,0xf8,0xfccf0006,0x33ffcfc,0xfffe0000,0xbfffffff,0xb6,0x7ff0000,0x7c,0xfffff800,0x10000,
-0x9fc80005,0x3d9f,0x20000,0xffff0000,0x7ff,0xff800,0xfbc00000,0x3eef,0xe000000,0xfff00000,0xfffffffb,0x10120200,0xff1e2000,0x10000000,0xb0002000,0x10480000,
-0x4e002000,0x2000,0x30002000,0x602100,0x18000000,0x24000400,0x7000000,0xf00,0x3000000,0x2a00000,0x3d7e0000,0xdf,0x40,0x6800000,0xe0000000,0x100000,
-0x20040000,0x200,0x1800000,0x9fe00001,0x3fff0000,0x10,0xc00,0xc0040,0x800000,0xfff70000,0x31021fd,0xfbffffff,0xbffffff,0x3ffffff,0x3f3fffff,0xaaff3f3f,
-0x3fffffff,0x1fdfffff,0xefcfffde,0x1fdc7fff,0x1fff0000,0x1ffe2,0x800,0xc000000,0x4000,0xe000,0x1210,0x50,0x292,0x333e005,0x333,0xf000,
-0x3c0f,0x38000,0x80000000,0xfc00,0x55555000,0x36db02a5,0x46100000,0x47900000,0x3ff08000,0xc0000000,0x30000,0x3ffff,0x3800,0x80000,1,0xc19d0000,
-2,0x400000,0x40000f5,0x5108000,0x5f7ffc00,0x7fdb
+0x9fc80005,0x3d9f,0x20000,0xffff0000,0x7ff,0x200ff800,0xfbc00000,0x3eef,0xe000000,0xfff80000,0xfffffffb,0x10120200,0xff1e2000,0x10000000,0xb0002000,0x40000000,
+0x10480000,0x4e002000,0x2000,0x30002000,0x602100,0x18000000,0x24000400,0x7000000,0xf00,0x3000000,0x2a00000,0x3d7e0000,0xdf,0x40,0x6800000,0xe0000000,
+0x100000,0x20040000,0x200,0x1800000,0x9fe00001,0x3fff0000,0x10,0xff800,0xc00,0xc0040,0x800000,0xfff70000,0x31021fd,0xfbffffff,0xbffffff,0x3ffffff,
+0x3f3fffff,0xaaff3f3f,0x3fffffff,0x1fdfffff,0xefcfffde,0x1fdc7fff,0x1fff0000,0x1ffe2,0x800,0xc000000,0x4000,0xe000,0x1210,0x50,0x292,0x333e005,
+0x333,0xf000,0x3c0f,0x38000,0x80000000,0xfc00,0x55555000,0x36db02a5,0x46100000,0x47900000,0x3ff08000,0xc0000000,0x30000,0x3ffff,0x3800,0x80000,
+1,0xc19d0000,2,0x400000,0x40000fd,0x5108000,0x5f7ffc00,0x7fdb
};
U_NAMESPACE_END
diff --git a/deps/icu-small/source/i18n/compactdecimalformat.cpp b/deps/icu-small/source/i18n/compactdecimalformat.cpp
index b2aacc45cda49c..4dd2241b23d0a6 100644
--- a/deps/icu-small/source/i18n/compactdecimalformat.cpp
+++ b/deps/icu-small/source/i18n/compactdecimalformat.cpp
@@ -1,1013 +1,75 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2018 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
-/*
-*******************************************************************************
-* Copyright (C) 1997-2015, International Business Machines Corporation and *
-* others. All Rights Reserved. *
-*******************************************************************************
-*
-* File COMPACTDECIMALFORMAT.CPP
-*
-********************************************************************************
-*/
+
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
-#include "charstr.h"
-#include "cstring.h"
-#include "digitlst.h"
-#include "mutex.h"
-#include "unicode/compactdecimalformat.h"
-#include "unicode/numsys.h"
-#include "unicode/plurrule.h"
-#include "unicode/ures.h"
-#include "ucln_in.h"
-#include "uhash.h"
-#include "umutex.h"
-#include "unicode/ures.h"
-#include "uresimp.h"
-
-// Maps locale name to CDFLocaleData struct.
-static UHashtable* gCompactDecimalData = NULL;
-static UMutex gCompactDecimalMetaLock = U_MUTEX_INITIALIZER;
-
-U_NAMESPACE_BEGIN
-
-static const int32_t MAX_DIGITS = 15;
-static const char gOther[] = "other";
-static const char gLatnTag[] = "latn";
-static const char gNumberElementsTag[] = "NumberElements";
-static const char gDecimalFormatTag[] = "decimalFormat";
-static const char gPatternsShort[] = "patternsShort";
-static const char gPatternsLong[] = "patternsLong";
-static const char gLatnPath[] = "NumberElements/latn";
-
-static const UChar u_0 = 0x30;
-static const UChar u_apos = 0x27;
-
-static const UChar kZero[] = {u_0};
-
-// Used to unescape single quotes.
-enum QuoteState {
- OUTSIDE,
- INSIDE_EMPTY,
- INSIDE_FULL
-};
-
-enum FallbackFlags {
- ANY = 0,
- MUST = 1,
- NOT_ROOT = 2
- // Next one will be 4 then 6 etc.
-};
-
-
-// CDFUnit represents a prefix-suffix pair for a particular variant
-// and log10 value.
-struct CDFUnit : public UMemory {
- UnicodeString prefix;
- UnicodeString suffix;
- inline CDFUnit() : prefix(), suffix() {
- prefix.setToBogus();
- }
- inline ~CDFUnit() {}
- inline UBool isSet() const {
- return !prefix.isBogus();
- }
- inline void markAsSet() {
- prefix.remove();
- }
-};
-
-// CDFLocaleStyleData contains formatting data for a particular locale
-// and style.
-class CDFLocaleStyleData : public UMemory {
- public:
- // What to divide by for each log10 value when formatting. These values
- // will be powers of 10. For English, would be:
- // 1, 1, 1, 1000, 1000, 1000, 1000000, 1000000, 1000000, 1000000000 ...
- double divisors[MAX_DIGITS];
- // Maps plural variants to CDFUnit[MAX_DIGITS] arrays.
- // To format a number x,
- // first compute log10(x). Compute displayNum = (x / divisors[log10(x)]).
- // Compute the plural variant for displayNum
- // (e.g zero, one, two, few, many, other).
- // Compute cdfUnits = unitsByVariant[pluralVariant].
- // Prefix and suffix to use at cdfUnits[log10(x)]
- UHashtable* unitsByVariant;
- // A flag for whether or not this CDFLocaleStyleData was loaded from the
- // Latin numbering system as a fallback from the locale numbering system.
- // This value is meaningless if the object is bogus or empty.
- UBool fromFallback;
- inline CDFLocaleStyleData() : unitsByVariant(NULL), fromFallback(FALSE) {
- uprv_memset(divisors, 0, sizeof(divisors));
- }
- ~CDFLocaleStyleData();
- // Init initializes this object.
- void Init(UErrorCode& status);
- inline UBool isBogus() const {
- return unitsByVariant == NULL;
- }
- void setToBogus();
- UBool isEmpty() {
- return unitsByVariant == NULL || unitsByVariant->count == 0;
- }
- private:
- CDFLocaleStyleData(const CDFLocaleStyleData&);
- CDFLocaleStyleData& operator=(const CDFLocaleStyleData&);
-};
-
-// CDFLocaleData contains formatting data for a particular locale.
-struct CDFLocaleData : public UMemory {
- CDFLocaleStyleData shortData;
- CDFLocaleStyleData longData;
- inline CDFLocaleData() : shortData(), longData() { }
- inline ~CDFLocaleData() { }
- // Init initializes this object.
- void Init(UErrorCode& status);
-};
-
-U_NAMESPACE_END
-
-U_CDECL_BEGIN
-
-static UBool U_CALLCONV cdf_cleanup(void) {
- if (gCompactDecimalData != NULL) {
- uhash_close(gCompactDecimalData);
- gCompactDecimalData = NULL;
- }
- return TRUE;
-}
-
-static void U_CALLCONV deleteCDFUnits(void* ptr) {
- delete [] (icu::CDFUnit*) ptr;
-}
-
-static void U_CALLCONV deleteCDFLocaleData(void* ptr) {
- delete (icu::CDFLocaleData*) ptr;
-}
-
-U_CDECL_END
+// Allow implicit conversion from char16_t* to UnicodeString for this file:
+// Helpful in toString methods and elsewhere.
+#define UNISTR_FROM_STRING_EXPLICIT
-U_NAMESPACE_BEGIN
+#include "unicode/compactdecimalformat.h"
+#include "number_mapper.h"
+#include "number_decimfmtprops.h"
-static UBool divisors_equal(const double* lhs, const double* rhs);
-static const CDFLocaleStyleData* getCDFLocaleStyleData(const Locale& inLocale, UNumberCompactStyle style, UErrorCode& status);
+using namespace icu;
-static const CDFLocaleStyleData* extractDataByStyleEnum(const CDFLocaleData& data, UNumberCompactStyle style, UErrorCode& status);
-static CDFLocaleData* loadCDFLocaleData(const Locale& inLocale, UErrorCode& status);
-static void load(const Locale& inLocale, CDFLocaleData* result, UErrorCode& status);
-static int32_t populatePrefixSuffix(const char* variant, int32_t log10Value, const UnicodeString& formatStr, UHashtable* result, UBool overwrite, UErrorCode& status);
-static double calculateDivisor(double power10, int32_t numZeros);
-static UBool onlySpaces(UnicodeString u);
-static void fixQuotes(UnicodeString& s);
-static void checkForOtherVariants(CDFLocaleStyleData* result, UErrorCode& status);
-static void fillInMissing(CDFLocaleStyleData* result);
-static int32_t computeLog10(double x, UBool inRange);
-static CDFUnit* createCDFUnit(const char* variant, int32_t log10Value, UHashtable* table, UErrorCode& status);
-static const CDFUnit* getCDFUnitFallback(const UHashtable* table, const UnicodeString& variant, int32_t log10Value);
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CompactDecimalFormat)
-CompactDecimalFormat::CompactDecimalFormat(
- const DecimalFormat& decimalFormat,
- const UHashtable* unitsByVariant,
- const double* divisors,
- PluralRules* pluralRules)
- : DecimalFormat(decimalFormat), _unitsByVariant(unitsByVariant), _divisors(divisors), _pluralRules(pluralRules) {
-}
-
-CompactDecimalFormat::CompactDecimalFormat(const CompactDecimalFormat& source)
- : DecimalFormat(source), _unitsByVariant(source._unitsByVariant), _divisors(source._divisors), _pluralRules(source._pluralRules->clone()) {
-}
-
-CompactDecimalFormat* U_EXPORT2
-CompactDecimalFormat::createInstance(
- const Locale& inLocale, UNumberCompactStyle style, UErrorCode& status) {
- LocalPointer decfmt((DecimalFormat*) NumberFormat::makeInstance(inLocale, UNUM_DECIMAL, TRUE, status));
- if (U_FAILURE(status)) {
- return NULL;
- }
- LocalPointer pluralRules(PluralRules::forLocale(inLocale, status));
- if (U_FAILURE(status)) {
- return NULL;
- }
- const CDFLocaleStyleData* data = getCDFLocaleStyleData(inLocale, style, status);
- if (U_FAILURE(status)) {
- return NULL;
- }
- CompactDecimalFormat* result =
- new CompactDecimalFormat(*decfmt, data->unitsByVariant, data->divisors, pluralRules.getAlias());
- if (result == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
- pluralRules.orphan();
- result->setMaximumSignificantDigits(3);
- result->setSignificantDigitsUsed(TRUE);
- result->setGroupingUsed(FALSE);
- return result;
-}
-
-CompactDecimalFormat&
-CompactDecimalFormat::operator=(const CompactDecimalFormat& rhs) {
- if (this != &rhs) {
- DecimalFormat::operator=(rhs);
- _unitsByVariant = rhs._unitsByVariant;
- _divisors = rhs._divisors;
- delete _pluralRules;
- _pluralRules = rhs._pluralRules->clone();
- }
- return *this;
-}
-
-CompactDecimalFormat::~CompactDecimalFormat() {
- delete _pluralRules;
-}
-
-Format*
-CompactDecimalFormat::clone(void) const {
- return new CompactDecimalFormat(*this);
+CompactDecimalFormat*
+CompactDecimalFormat::createInstance(const Locale& inLocale, UNumberCompactStyle style,
+ UErrorCode& status) {
+ return new CompactDecimalFormat(inLocale, style, status);
}
-UBool
-CompactDecimalFormat::operator==(const Format& that) const {
- if (this == &that) {
- return TRUE;
- }
- return (DecimalFormat::operator==(that) && eqHelper((const CompactDecimalFormat&) that));
-}
-
-UBool
-CompactDecimalFormat::eqHelper(const CompactDecimalFormat& that) const {
- return uhash_equals(_unitsByVariant, that._unitsByVariant) && divisors_equal(_divisors, that._divisors) && (*_pluralRules == *that._pluralRules);
-}
-
-UnicodeString&
-CompactDecimalFormat::format(
- double number,
- UnicodeString& appendTo,
- FieldPosition& pos) const {
- UErrorCode status = U_ZERO_ERROR;
- return format(number, appendTo, pos, status);
-}
-
-UnicodeString&
-CompactDecimalFormat::format(
- double number,
- UnicodeString& appendTo,
- FieldPosition& pos,
- UErrorCode &status) const {
- if (U_FAILURE(status)) {
- return appendTo;
- }
- DigitList orig, rounded;
- orig.set(number);
- UBool isNegative;
- _round(orig, rounded, isNegative, status);
- if (U_FAILURE(status)) {
- return appendTo;
- }
- double roundedDouble = rounded.getDouble();
- if (isNegative) {
- roundedDouble = -roundedDouble;
- }
- int32_t baseIdx = computeLog10(roundedDouble, TRUE);
- double numberToFormat = roundedDouble / _divisors[baseIdx];
- UnicodeString variant = _pluralRules->select(numberToFormat);
- if (isNegative) {
- numberToFormat = -numberToFormat;
- }
- const CDFUnit* unit = getCDFUnitFallback(_unitsByVariant, variant, baseIdx);
- appendTo += unit->prefix;
- DecimalFormat::format(numberToFormat, appendTo, pos);
- appendTo += unit->suffix;
- return appendTo;
-}
-
-UnicodeString&
-CompactDecimalFormat::format(
- double /* number */,
- UnicodeString& appendTo,
- FieldPositionIterator* /* posIter */,
- UErrorCode& status) const {
- status = U_UNSUPPORTED_ERROR;
- return appendTo;
-}
-
-UnicodeString&
-CompactDecimalFormat::format(
- int32_t number,
- UnicodeString& appendTo,
- FieldPosition& pos) const {
- return format((double) number, appendTo, pos);
-}
-
-UnicodeString&
-CompactDecimalFormat::format(
- int32_t number,
- UnicodeString& appendTo,
- FieldPosition& pos,
- UErrorCode &status) const {
- return format((double) number, appendTo, pos, status);
-}
-
-UnicodeString&
-CompactDecimalFormat::format(
- int32_t /* number */,
- UnicodeString& appendTo,
- FieldPositionIterator* /* posIter */,
- UErrorCode& status) const {
- status = U_UNSUPPORTED_ERROR;
- return appendTo;
-}
-
-UnicodeString&
-CompactDecimalFormat::format(
- int64_t number,
- UnicodeString& appendTo,
- FieldPosition& pos) const {
- return format((double) number, appendTo, pos);
-}
-
-UnicodeString&
-CompactDecimalFormat::format(
- int64_t number,
- UnicodeString& appendTo,
- FieldPosition& pos,
- UErrorCode &status) const {
- return format((double) number, appendTo, pos, status);
+CompactDecimalFormat::CompactDecimalFormat(const Locale& inLocale, UNumberCompactStyle style,
+ UErrorCode& status)
+ : DecimalFormat(new DecimalFormatSymbols(inLocale, status), status) {
+ if (U_FAILURE(status)) return;
+ // Minimal properties: let the non-shim code path do most of the logic for us.
+ fields->properties->compactStyle = style;
+ fields->properties->groupingSize = -2; // do not forward grouping information
+ fields->properties->minimumGroupingDigits = 2;
+ touch(status);
}
-UnicodeString&
-CompactDecimalFormat::format(
- int64_t /* number */,
- UnicodeString& appendTo,
- FieldPositionIterator* /* posIter */,
- UErrorCode& status) const {
- status = U_UNSUPPORTED_ERROR;
- return appendTo;
-}
+CompactDecimalFormat::CompactDecimalFormat(const CompactDecimalFormat& source) = default;
-UnicodeString&
-CompactDecimalFormat::format(
- StringPiece /* number */,
- UnicodeString& appendTo,
- FieldPositionIterator* /* posIter */,
- UErrorCode& status) const {
- status = U_UNSUPPORTED_ERROR;
- return appendTo;
-}
+CompactDecimalFormat::~CompactDecimalFormat() = default;
-UnicodeString&
-CompactDecimalFormat::format(
- const DigitList& /* number */,
- UnicodeString& appendTo,
- FieldPositionIterator* /* posIter */,
- UErrorCode& status) const {
- status = U_UNSUPPORTED_ERROR;
- return appendTo;
+CompactDecimalFormat& CompactDecimalFormat::operator=(const CompactDecimalFormat& rhs) {
+ DecimalFormat::operator=(rhs);
+ return *this;
}
-UnicodeString&
-CompactDecimalFormat::format(const DigitList& /* number */,
- UnicodeString& appendTo,
- FieldPosition& /* pos */,
- UErrorCode& status) const {
- status = U_UNSUPPORTED_ERROR;
- return appendTo;
+Format* CompactDecimalFormat::clone() const {
+ return new CompactDecimalFormat(*this);
}
void
CompactDecimalFormat::parse(
- const UnicodeString& /* text */,
- Formattable& /* result */,
- ParsePosition& /* parsePosition */) const {
+ const UnicodeString& /* text */,
+ Formattable& /* result */,
+ ParsePosition& /* parsePosition */) const {
}
void
CompactDecimalFormat::parse(
- const UnicodeString& /* text */,
- Formattable& /* result */,
- UErrorCode& status) const {
- status = U_UNSUPPORTED_ERROR;
+ const UnicodeString& /* text */,
+ Formattable& /* result */,
+ UErrorCode& status) const {
+ status = U_UNSUPPORTED_ERROR;
}
CurrencyAmount*
CompactDecimalFormat::parseCurrency(
- const UnicodeString& /* text */,
- ParsePosition& /* pos */) const {
- return NULL;
-}
-
-void CDFLocaleStyleData::Init(UErrorCode& status) {
- if (unitsByVariant != NULL) {
- return;
- }
- unitsByVariant = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
- if (U_FAILURE(status)) {
- return;
- }
- uhash_setKeyDeleter(unitsByVariant, uprv_free);
- uhash_setValueDeleter(unitsByVariant, deleteCDFUnits);
-}
-
-CDFLocaleStyleData::~CDFLocaleStyleData() {
- setToBogus();
-}
-
-void CDFLocaleStyleData::setToBogus() {
- if (unitsByVariant != NULL) {
- uhash_close(unitsByVariant);
- unitsByVariant = NULL;
- }
-}
-
-void CDFLocaleData::Init(UErrorCode& status) {
- shortData.Init(status);
- if (U_FAILURE(status)) {
- return;
- }
- longData.Init(status);
-}
-
-// Helper method for operator=
-static UBool divisors_equal(const double* lhs, const double* rhs) {
- for (int32_t i = 0; i < MAX_DIGITS; ++i) {
- if (lhs[i] != rhs[i]) {
- return FALSE;
- }
- }
- return TRUE;
-}
-
-// getCDFLocaleStyleData returns pointer to formatting data for given locale and
-// style within the global cache. On cache miss, getCDFLocaleStyleData loads
-// the data from CLDR into the global cache before returning the pointer. If a
-// UNUM_LONG data is requested for a locale, and that locale does not have
-// UNUM_LONG data, getCDFLocaleStyleData will fall back to UNUM_SHORT data for
-// that locale.
-static const CDFLocaleStyleData* getCDFLocaleStyleData(const Locale& inLocale, UNumberCompactStyle style, UErrorCode& status) {
- if (U_FAILURE(status)) {
- return NULL;
- }
- CDFLocaleData* result = NULL;
- const char* key = inLocale.getName();
- {
- Mutex lock(&gCompactDecimalMetaLock);
- if (gCompactDecimalData == NULL) {
- gCompactDecimalData = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
- if (U_FAILURE(status)) {
- return NULL;
- }
- uhash_setKeyDeleter(gCompactDecimalData, uprv_free);
- uhash_setValueDeleter(gCompactDecimalData, deleteCDFLocaleData);
- ucln_i18n_registerCleanup(UCLN_I18N_CDFINFO, cdf_cleanup);
- } else {
- result = (CDFLocaleData*) uhash_get(gCompactDecimalData, key);
- }
- }
- if (result != NULL) {
- return extractDataByStyleEnum(*result, style, status);
- }
-
- result = loadCDFLocaleData(inLocale, status);
- if (U_FAILURE(status)) {
- return NULL;
- }
-
- {
- Mutex lock(&gCompactDecimalMetaLock);
- CDFLocaleData* temp = (CDFLocaleData*) uhash_get(gCompactDecimalData, key);
- if (temp != NULL) {
- delete result;
- result = temp;
- } else {
- uhash_put(gCompactDecimalData, uprv_strdup(key), (void*) result, &status);
- if (U_FAILURE(status)) {
- return NULL;
- }
- }
- }
- return extractDataByStyleEnum(*result, style, status);
-}
-
-static const CDFLocaleStyleData* extractDataByStyleEnum(const CDFLocaleData& data, UNumberCompactStyle style, UErrorCode& status) {
- switch (style) {
- case UNUM_SHORT:
- return &data.shortData;
- case UNUM_LONG:
- if (!data.longData.isBogus()) {
- return &data.longData;
- }
- return &data.shortData;
- default:
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return NULL;
- }
-}
-
-// loadCDFLocaleData loads formatting data from CLDR for a given locale. The
-// caller owns the returned pointer.
-static CDFLocaleData* loadCDFLocaleData(const Locale& inLocale, UErrorCode& status) {
- if (U_FAILURE(status)) {
- return NULL;
- }
- CDFLocaleData* result = new CDFLocaleData;
- if (result == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
- result->Init(status);
- if (U_FAILURE(status)) {
- delete result;
- return NULL;
- }
-
- load(inLocale, result, status);
-
- if (U_FAILURE(status)) {
- delete result;
- return NULL;
- }
- return result;
-}
-
-namespace {
-
-struct CmptDecDataSink : public ResourceSink {
-
- CDFLocaleData& dataBundle; // Where to save values when they are read
- UBool isLatin; // Whether or not we are traversing the Latin tree
- UBool isFallback; // Whether or not we are traversing the Latin tree as fallback
-
- enum EPatternsTableKey { PATTERNS_SHORT, PATTERNS_LONG };
- enum EFormatsTableKey { DECIMAL_FORMAT, CURRENCY_FORMAT };
-
- /*
- * NumberElements{ <-- top (numbering system table)
- * latn{ <-- patternsTable (one per numbering system)
- * patternsLong{ <-- formatsTable (one per pattern)
- * decimalFormat{ <-- powersOfTenTable (one per format)
- * 1000{ <-- pluralVariantsTable (one per power of ten)
- * one{"0 thousand"} <-- plural variant and template
- */
-
- CmptDecDataSink(CDFLocaleData& _dataBundle)
- : dataBundle(_dataBundle), isLatin(FALSE), isFallback(FALSE) {}
- virtual ~CmptDecDataSink();
-
- virtual void put(const char *key, ResourceValue &value, UBool isRoot, UErrorCode &errorCode) {
- // SPECIAL CASE: Don't consume root in the non-Latin numbering system
- if (isRoot && !isLatin) { return; }
-
- ResourceTable patternsTable = value.getTable(errorCode);
- if (U_FAILURE(errorCode)) { return; }
- for (int i1 = 0; patternsTable.getKeyAndValue(i1, key, value); ++i1) {
-
- // Check for patternsShort or patternsLong
- EPatternsTableKey patternsTableKey;
- if (uprv_strcmp(key, gPatternsShort) == 0) {
- patternsTableKey = PATTERNS_SHORT;
- } else if (uprv_strcmp(key, gPatternsLong) == 0) {
- patternsTableKey = PATTERNS_LONG;
- } else {
- continue;
- }
-
- // Traverse into the formats table
- ResourceTable formatsTable = value.getTable(errorCode);
- if (U_FAILURE(errorCode)) { return; }
- for (int i2 = 0; formatsTable.getKeyAndValue(i2, key, value); ++i2) {
-
- // Check for decimalFormat or currencyFormat
- EFormatsTableKey formatsTableKey;
- if (uprv_strcmp(key, gDecimalFormatTag) == 0) {
- formatsTableKey = DECIMAL_FORMAT;
- // TODO: Enable this statement when currency support is added
- // } else if (uprv_strcmp(key, gCurrencyFormat) == 0) {
- // formatsTableKey = CURRENCY_FORMAT;
- } else {
- continue;
- }
-
- // Set the current style and destination based on the two keys
- UNumberCompactStyle style;
- CDFLocaleStyleData* destination = NULL;
- if (patternsTableKey == PATTERNS_LONG
- && formatsTableKey == DECIMAL_FORMAT) {
- style = UNUM_LONG;
- destination = &dataBundle.longData;
- } else if (patternsTableKey == PATTERNS_SHORT
- && formatsTableKey == DECIMAL_FORMAT) {
- style = UNUM_SHORT;
- destination = &dataBundle.shortData;
- // TODO: Enable the following statements when currency support is added
- // } else if (patternsTableKey == PATTERNS_SHORT
- // && formatsTableKey == CURRENCY_FORMAT) {
- // style = UNUM_SHORT_CURRENCY; // or whatever the enum gets named
- // destination = &dataBundle.shortCurrencyData;
- // } else {
- // // Silently ignore this case
- // continue;
- }
-
- // SPECIAL CASE: RULES FOR WHETHER OR NOT TO CONSUME THIS TABLE:
- // 1) Don't consume longData if shortData was consumed from the non-Latin
- // locale numbering system
- // 2) Don't consume longData for the first time if this is the root bundle and
- // shortData is already populated from a more specific locale. Note that if
- // both longData and shortData are both only in root, longData will be
- // consumed since it is alphabetically before shortData in the bundle.
- if (isFallback
- && style == UNUM_LONG
- && !dataBundle.shortData.isEmpty()
- && !dataBundle.shortData.fromFallback) {
- continue;
- }
- if (isRoot
- && style == UNUM_LONG
- && dataBundle.longData.isEmpty()
- && !dataBundle.shortData.isEmpty()) {
- continue;
- }
-
- // Set the "fromFallback" flag on the data object
- destination->fromFallback = isFallback;
-
- // Traverse into the powers of ten table
- ResourceTable powersOfTenTable = value.getTable(errorCode);
- if (U_FAILURE(errorCode)) { return; }
- for (int i3 = 0; powersOfTenTable.getKeyAndValue(i3, key, value); ++i3) {
-
- // The key will always be some even power of 10. e.g 10000.
- char* endPtr = NULL;
- double power10 = uprv_strtod(key, &endPtr);
- if (*endPtr != 0) {
- errorCode = U_INTERNAL_PROGRAM_ERROR;
- return;
- }
- int32_t log10Value = computeLog10(power10, FALSE);
-
- // Silently ignore divisors that are too big.
- if (log10Value >= MAX_DIGITS) continue;
-
- // Iterate over the plural variants ("one", "other", etc)
- ResourceTable pluralVariantsTable = value.getTable(errorCode);
- if (U_FAILURE(errorCode)) { return; }
- for (int i4 = 0; pluralVariantsTable.getKeyAndValue(i4, key, value); ++i4) {
- const char* pluralVariant = key;
- const UnicodeString formatStr = value.getUnicodeString(errorCode);
-
- // Copy the data into the in-memory data bundle (do not overwrite
- // existing values)
- int32_t numZeros = populatePrefixSuffix(
- pluralVariant, log10Value, formatStr,
- destination->unitsByVariant, FALSE, errorCode);
-
- // If populatePrefixSuffix returns -1, it means that this key has been
- // encountered already.
- if (numZeros < 0) {
- continue;
- }
-
- // Set the divisor, which is based on the number of zeros in the template
- // string. If the divisor from here is different from the one previously
- // stored, it means that the number of zeros in different plural variants
- // differs; throw an exception.
- // TODO: How should I check for floating-point errors here?
- // Is there a good reason why "divisor" is double and not long like Java?
- double divisor = calculateDivisor(power10, numZeros);
- if (destination->divisors[log10Value] != 0.0
- && destination->divisors[log10Value] != divisor) {
- errorCode = U_INTERNAL_PROGRAM_ERROR;
- return;
- }
- destination->divisors[log10Value] = divisor;
- }
- }
- }
- }
- }
-};
-
-// Virtual destructors must be defined out of line.
-CmptDecDataSink::~CmptDecDataSink() {}
-
-} // namespace
-
-static void load(const Locale& inLocale, CDFLocaleData* result, UErrorCode& status) {
- LocalPointer ns(NumberingSystem::createInstance(inLocale, status));
- if (U_FAILURE(status)) {
- return;
- }
- const char* nsName = ns->getName();
-
- LocalUResourceBundlePointer resource(ures_open(NULL, inLocale.getName(), &status));
- if (U_FAILURE(status)) {
- return;
- }
- CmptDecDataSink sink(*result);
- sink.isFallback = FALSE;
-
- // First load the number elements data if nsName is not Latin.
- if (uprv_strcmp(nsName, gLatnTag) != 0) {
- sink.isLatin = FALSE;
- CharString path;
- path.append(gNumberElementsTag, status)
- .append('/', status)
- .append(nsName, status);
- ures_getAllItemsWithFallback(resource.getAlias(), path.data(), sink, status);
- if (status == U_MISSING_RESOURCE_ERROR) {
- // Silently ignore and use Latin
- status = U_ZERO_ERROR;
- } else if (U_FAILURE(status)) {
- return;
- }
- sink.isFallback = TRUE;
- }
-
- // Now load Latin.
- sink.isLatin = TRUE;
- ures_getAllItemsWithFallback(resource.getAlias(), gLatnPath, sink, status);
- if (U_FAILURE(status)) return;
-
- // If longData is empty, default it to be equal to shortData
- if (result->longData.isEmpty()) {
- result->longData.setToBogus();
- }
-
- // Check for "other" variants in each of the three data classes, and resolve missing elements.
-
- if (!result->longData.isBogus()) {
- checkForOtherVariants(&result->longData, status);
- if (U_FAILURE(status)) return;
- fillInMissing(&result->longData);
- }
-
- checkForOtherVariants(&result->shortData, status);
- if (U_FAILURE(status)) return;
- fillInMissing(&result->shortData);
-
- // TODO: Enable this statement when currency support is added
- // checkForOtherVariants(&result->shortCurrencyData, status);
- // if (U_FAILURE(status)) return;
- // fillInMissing(&result->shortCurrencyData);
-}
-
-// populatePrefixSuffix Adds a specific prefix-suffix pair to result for a
-// given variant and log10 value.
-// variant is 'zero', 'one', 'two', 'few', 'many', or 'other'.
-// formatStr is the format string from which the prefix and suffix are
-// extracted. It is usually of form 'Pefix 000 suffix'.
-// populatePrefixSuffix returns the number of 0's found in formatStr
-// before the decimal point.
-// In the special case that formatStr contains only spaces for prefix
-// and suffix, populatePrefixSuffix returns log10Value + 1.
-static int32_t populatePrefixSuffix(
- const char* variant, int32_t log10Value, const UnicodeString& formatStr, UHashtable* result, UBool overwrite, UErrorCode& status) {
- if (U_FAILURE(status)) {
- return 0;
- }
-
- // ICU 59 HACK: Ignore negative part of format string, mimicking ICU 58 behavior.
- // TODO(sffc): Make sure this is fixed during the overhaul port in ICU 60.
- int32_t semiPos = formatStr.indexOf(';', 0);
- if (semiPos == -1) {
- semiPos = formatStr.length();
- }
- UnicodeString positivePart = formatStr.tempSubString(0, semiPos);
-
- int32_t firstIdx = positivePart.indexOf(kZero, UPRV_LENGTHOF(kZero), 0);
- // We must have 0's in format string.
- if (firstIdx == -1) {
- status = U_INTERNAL_PROGRAM_ERROR;
- return 0;
- }
- int32_t lastIdx = positivePart.lastIndexOf(kZero, UPRV_LENGTHOF(kZero), firstIdx);
- CDFUnit* unit = createCDFUnit(variant, log10Value, result, status);
- if (U_FAILURE(status)) {
- return 0;
- }
-
- // Return -1 if we are not overwriting an existing value
- if (unit->isSet() && !overwrite) {
- return -1;
- }
- unit->markAsSet();
-
- // Everything up to first 0 is the prefix
- unit->prefix = positivePart.tempSubString(0, firstIdx);
- fixQuotes(unit->prefix);
- // Everything beyond the last 0 is the suffix
- unit->suffix = positivePart.tempSubString(lastIdx + 1);
- fixQuotes(unit->suffix);
-
- // If there is effectively no prefix or suffix, ignore the actual number of
- // 0's and act as if the number of 0's matches the size of the number.
- if (onlySpaces(unit->prefix) && onlySpaces(unit->suffix)) {
- return log10Value + 1;
- }
-
- // Calculate number of zeros before decimal point
- int32_t idx = firstIdx + 1;
- while (idx <= lastIdx && positivePart.charAt(idx) == u_0) {
- ++idx;
- }
- return (idx - firstIdx);
-}
-
-// Calculate a divisor based on the magnitude and number of zeros in the
-// template string.
-static double calculateDivisor(double power10, int32_t numZeros) {
- double divisor = power10;
- for (int32_t i = 1; i < numZeros; ++i) {
- divisor /= 10.0;
- }
- return divisor;
-}
-
-static UBool onlySpaces(UnicodeString u) {
- return u.trim().length() == 0;
+ const UnicodeString& /* text */,
+ ParsePosition& /* pos */) const {
+ return nullptr;
}
-// fixQuotes unescapes single quotes. Don''t -> Don't. Letter 'j' -> Letter j.
-// Modifies s in place.
-static void fixQuotes(UnicodeString& s) {
- QuoteState state = OUTSIDE;
- int32_t len = s.length();
- int32_t dest = 0;
- for (int32_t i = 0; i < len; ++i) {
- UChar ch = s.charAt(i);
- if (ch == u_apos) {
- if (state == INSIDE_EMPTY) {
- s.setCharAt(dest, ch);
- ++dest;
- }
- } else {
- s.setCharAt(dest, ch);
- ++dest;
- }
-
- // Update state
- switch (state) {
- case OUTSIDE:
- state = ch == u_apos ? INSIDE_EMPTY : OUTSIDE;
- break;
- case INSIDE_EMPTY:
- case INSIDE_FULL:
- state = ch == u_apos ? OUTSIDE : INSIDE_FULL;
- break;
- default:
- break;
- }
- }
- s.truncate(dest);
-}
-
-// Checks to make sure that an "other" variant is present in all
-// powers of 10.
-static void checkForOtherVariants(CDFLocaleStyleData* result,
- UErrorCode& status) {
- if (result == NULL || result->unitsByVariant == NULL) {
- return;
- }
-
- const CDFUnit* otherByBase =
- (const CDFUnit*) uhash_get(result->unitsByVariant, gOther);
- if (otherByBase == NULL) {
- status = U_INTERNAL_PROGRAM_ERROR;
- return;
- }
-
- // Check all other plural variants, and make sure that if
- // any of them are populated, then other is also populated
- int32_t pos = UHASH_FIRST;
- const UHashElement* element;
- while ((element = uhash_nextElement(result->unitsByVariant, &pos)) != NULL) {
- CDFUnit* variantsByBase = (CDFUnit*) element->value.pointer;
- if (variantsByBase == otherByBase) continue;
- for (int32_t log10Value = 0; log10Value < MAX_DIGITS; ++log10Value) {
- if (variantsByBase[log10Value].isSet()
- && !otherByBase[log10Value].isSet()) {
- status = U_INTERNAL_PROGRAM_ERROR;
- return;
- }
- }
- }
-}
-
-// fillInMissing ensures that the data in result is complete.
-// result data is complete if for each variant in result, there exists
-// a prefix-suffix pair for each log10 value and there also exists
-// a divisor for each log10 value.
-//
-// First this function figures out for which log10 values, the other
-// variant already had data. These are the same log10 values defined
-// in CLDR.
-//
-// For each log10 value not defined in CLDR, it uses the divisor for
-// the last defined log10 value or 1.
-//
-// Then for each variant, it does the following. For each log10
-// value not defined in CLDR, copy the prefix-suffix pair from the
-// previous log10 value. If log10 value is defined in CLDR but is
-// missing from given variant, copy the prefix-suffix pair for that
-// log10 value from the 'other' variant.
-static void fillInMissing(CDFLocaleStyleData* result) {
- const CDFUnit* otherUnits =
- (const CDFUnit*) uhash_get(result->unitsByVariant, gOther);
- UBool definedInCLDR[MAX_DIGITS];
- double lastDivisor = 1.0;
- for (int32_t i = 0; i < MAX_DIGITS; ++i) {
- if (!otherUnits[i].isSet()) {
- result->divisors[i] = lastDivisor;
- definedInCLDR[i] = FALSE;
- } else {
- lastDivisor = result->divisors[i];
- definedInCLDR[i] = TRUE;
- }
- }
- // Iterate over each variant.
- int32_t pos = UHASH_FIRST;
- const UHashElement* element = uhash_nextElement(result->unitsByVariant, &pos);
- for (;element != NULL; element = uhash_nextElement(result->unitsByVariant, &pos)) {
- CDFUnit* units = (CDFUnit*) element->value.pointer;
- for (int32_t i = 0; i < MAX_DIGITS; ++i) {
- if (definedInCLDR[i]) {
- if (!units[i].isSet()) {
- units[i] = otherUnits[i];
- }
- } else {
- if (i == 0) {
- units[0].markAsSet();
- } else {
- units[i] = units[i - 1];
- }
- }
- }
- }
-}
-
-// computeLog10 computes floor(log10(x)). If inRange is TRUE, the biggest
-// value computeLog10 will return MAX_DIGITS -1 even for
-// numbers > 10^MAX_DIGITS. If inRange is FALSE, computeLog10 will return
-// up to MAX_DIGITS.
-static int32_t computeLog10(double x, UBool inRange) {
- int32_t result = 0;
- int32_t max = inRange ? MAX_DIGITS - 1 : MAX_DIGITS;
- while (x >= 10.0) {
- x /= 10.0;
- ++result;
- if (result == max) {
- break;
- }
- }
- return result;
-}
-
-// createCDFUnit returns a pointer to the prefix-suffix pair for a given
-// variant and log10 value within table. If no such prefix-suffix pair is
-// stored in table, one is created within table before returning pointer.
-static CDFUnit* createCDFUnit(const char* variant, int32_t log10Value, UHashtable* table, UErrorCode& status) {
- if (U_FAILURE(status)) {
- return NULL;
- }
- CDFUnit *cdfUnit = (CDFUnit*) uhash_get(table, variant);
- if (cdfUnit == NULL) {
- cdfUnit = new CDFUnit[MAX_DIGITS];
- if (cdfUnit == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
- uhash_put(table, uprv_strdup(variant), cdfUnit, &status);
- if (U_FAILURE(status)) {
- return NULL;
- }
- }
- CDFUnit* result = &cdfUnit[log10Value];
- return result;
-}
-
-// getCDFUnitFallback returns a pointer to the prefix-suffix pair for a given
-// variant and log10 value within table. If the given variant doesn't exist, it
-// falls back to the OTHER variant. Therefore, this method will always return
-// some non-NULL value.
-static const CDFUnit* getCDFUnitFallback(const UHashtable* table, const UnicodeString& variant, int32_t log10Value) {
- CharString cvariant;
- UErrorCode status = U_ZERO_ERROR;
- const CDFUnit *cdfUnit = NULL;
- cvariant.appendInvariantChars(variant, status);
- if (!U_FAILURE(status)) {
- cdfUnit = (const CDFUnit*) uhash_get(table, cvariant.data());
- }
- if (cdfUnit == NULL) {
- cdfUnit = (const CDFUnit*) uhash_get(table, gOther);
- }
- return &cdfUnit[log10Value];
-}
-U_NAMESPACE_END
-#endif
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/deps/icu-small/source/i18n/currpinf.cpp b/deps/icu-small/source/i18n/currpinf.cpp
index 5d3ca620891500..6b1efd5f4da721 100644
--- a/deps/icu-small/source/i18n/currpinf.cpp
+++ b/deps/icu-small/source/i18n/currpinf.cpp
@@ -203,6 +203,9 @@ CurrencyPluralInfo::setCurrencyPluralPattern(const UnicodeString& pluralCount,
const UnicodeString& pattern,
UErrorCode& status) {
if (U_SUCCESS(status)) {
+ UnicodeString* oldValue = static_cast(
+ fPluralCountToCurrencyUnitPattern->get(pluralCount));
+ delete oldValue;
fPluralCountToCurrencyUnitPattern->put(pluralCount, new UnicodeString(pattern), status);
}
}
diff --git a/deps/icu-small/source/i18n/currunit.cpp b/deps/icu-small/source/i18n/currunit.cpp
index 83429c01694acc..6d8d1cd6c6f97f 100644
--- a/deps/icu-small/source/i18n/currunit.cpp
+++ b/deps/icu-small/source/i18n/currunit.cpp
@@ -17,21 +17,32 @@
#include "unicode/currunit.h"
#include "unicode/ustring.h"
#include "cstring.h"
+#include "uinvchar.h"
+
+static constexpr char16_t kDefaultCurrency[] = u"XXX";
U_NAMESPACE_BEGIN
CurrencyUnit::CurrencyUnit(ConstChar16Ptr _isoCode, UErrorCode& ec) {
- *isoCode = 0;
- if (U_SUCCESS(ec)) {
- if (_isoCode != nullptr && u_strlen(_isoCode)==3) {
- u_strcpy(isoCode, _isoCode);
- char simpleIsoCode[4];
- u_UCharsToChars(isoCode, simpleIsoCode, 4);
- initCurrency(simpleIsoCode);
- } else {
- ec = U_ILLEGAL_ARGUMENT_ERROR;
- }
+ // The constructor always leaves the CurrencyUnit in a valid state (with a 3-character currency code).
+ // Note: in ICU4J Currency.getInstance(), we check string length for 3, but in ICU4C we allow a
+ // non-NUL-terminated string to be passed as an argument, so it is not possible to check length.
+ const char16_t* isoCodeToUse;
+ if (U_FAILURE(ec) || _isoCode == nullptr) {
+ isoCodeToUse = kDefaultCurrency;
+ } else if (!uprv_isInvariantUString(_isoCode, 3)) {
+ // TODO: Perform a more strict ASCII check like in ICU4J isAlpha3Code?
+ isoCodeToUse = kDefaultCurrency;
+ ec = U_INVARIANT_CONVERSION_ERROR;
+ } else {
+ isoCodeToUse = _isoCode;
}
+ // TODO: Perform uppercasing here like in ICU4J Currency.getInstance()?
+ uprv_memcpy(isoCode, isoCodeToUse, sizeof(UChar) * 3);
+ isoCode[3] = 0;
+ char simpleIsoCode[4];
+ u_UCharsToChars(isoCode, simpleIsoCode, 4);
+ initCurrency(simpleIsoCode);
}
CurrencyUnit::CurrencyUnit(const CurrencyUnit& other) : MeasureUnit(other) {
@@ -52,7 +63,7 @@ CurrencyUnit::CurrencyUnit(const MeasureUnit& other, UErrorCode& ec) : MeasureUn
}
CurrencyUnit::CurrencyUnit() : MeasureUnit() {
- u_strcpy(isoCode, u"XXX");
+ u_strcpy(isoCode, kDefaultCurrency);
char simpleIsoCode[4];
u_UCharsToChars(isoCode, simpleIsoCode, 4);
initCurrency(simpleIsoCode);
diff --git a/deps/icu-small/source/i18n/dcfmtimp.h b/deps/icu-small/source/i18n/dcfmtimp.h
deleted file mode 100644
index e582efb344b3b8..00000000000000
--- a/deps/icu-small/source/i18n/dcfmtimp.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// © 2016 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html
-/*
-********************************************************************************
-* Copyright (C) 2012-2014, International Business Machines
-* Corporation and others. All Rights Reserved.
-********************************************************************************/
-
-#ifndef DCFMTIMP_H
-#define DCFMTIMP_H
-
-#include "unicode/utypes.h"
-
-
-#if UCONFIG_FORMAT_FASTPATHS_49
-
-U_NAMESPACE_BEGIN
-
-enum EDecimalFormatFastpathStatus {
- kFastpathNO = 0,
- kFastpathYES = 1,
- kFastpathUNKNOWN = 2, /* not yet set */
- kFastpathMAYBE = 3 /* depends on value being formatted. */
-};
-
-/**
- * Must be smaller than DecimalFormat::fReserved
- */
-struct DecimalFormatInternal {
- uint8_t fFastFormatStatus;
- uint8_t fFastParseStatus;
-
- DecimalFormatInternal &operator=(const DecimalFormatInternal& rhs) {
- fFastParseStatus = rhs.fFastParseStatus;
- fFastFormatStatus = rhs.fFastFormatStatus;
- return *this;
- }
-#ifdef FMT_DEBUG
- void dump() const {
- printf("DecimalFormatInternal: fFastFormatStatus=%c, fFastParseStatus=%c\n",
- "NY?"[(int)fFastFormatStatus&3],
- "NY?"[(int)fFastParseStatus&3]
- );
- }
-#endif
-};
-
-
-
-U_NAMESPACE_END
-
-#endif
-
-#endif
diff --git a/deps/icu-small/source/i18n/dcfmtsym.cpp b/deps/icu-small/source/i18n/dcfmtsym.cpp
index 680c3120a1e0f9..5a432aec8e4df0 100644
--- a/deps/icu-small/source/i18n/dcfmtsym.cpp
+++ b/deps/icu-small/source/i18n/dcfmtsym.cpp
@@ -66,7 +66,7 @@ static const UChar INTL_CURRENCY_SYMBOL_STR[] = {0xa4, 0xa4, 0};
static const char *gNumberElementKeys[DecimalFormatSymbols::kFormatSymbolCount] = {
"decimal",
"group",
- "list",
+ NULL, /* #11897: the symbol is NOT the pattern separator symbol */
"percentSign",
NULL, /* Native zero digit is deprecated from CLDR - get it from the numbering system */
NULL, /* Pattern digit character is deprecated from CLDR - use # by default always */
@@ -98,7 +98,7 @@ static const char *gNumberElementKeys[DecimalFormatSymbols::kFormatSymbolCount]
// Initializes this with the decimal format symbols in the default locale.
DecimalFormatSymbols::DecimalFormatSymbols(UErrorCode& status)
- : UObject(), locale() {
+ : UObject(), locale(), currPattern(NULL) {
initialize(locale, status, TRUE);
}
@@ -106,12 +106,12 @@ DecimalFormatSymbols::DecimalFormatSymbols(UErrorCode& status)
// Initializes this with the decimal format symbols in the desired locale.
DecimalFormatSymbols::DecimalFormatSymbols(const Locale& loc, UErrorCode& status)
- : UObject(), locale(loc) {
+ : UObject(), locale(loc), currPattern(NULL) {
initialize(locale, status);
}
DecimalFormatSymbols::DecimalFormatSymbols(const Locale& loc, const NumberingSystem& ns, UErrorCode& status)
- : UObject(), locale(loc) {
+ : UObject(), locale(loc), currPattern(NULL) {
initialize(locale, status, FALSE, &ns);
}
@@ -349,7 +349,6 @@ DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status,
{
if (U_FAILURE(status)) { return; }
*validLocale = *actualLocale = 0;
- currPattern = NULL;
// First initialize all the symbols to the fallbacks for anything we can't find
initialize();
@@ -477,6 +476,7 @@ DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status,
UErrorCode localStatus = U_ZERO_ERROR;
uccLen = ucurr_forLocale(locName, ucc, uccLen, &localStatus);
+ // TODO: Currency pattern data loading is duplicated in number_formatimpl.cpp
if(U_SUCCESS(localStatus) && uccLen > 0) {
char cc[4]={0};
u_UCharsToChars(ucc, cc, uccLen);
diff --git a/deps/icu-small/source/i18n/decfmtst.cpp b/deps/icu-small/source/i18n/decfmtst.cpp
deleted file mode 100644
index 5943affad4eb06..00000000000000
--- a/deps/icu-small/source/i18n/decfmtst.cpp
+++ /dev/null
@@ -1,251 +0,0 @@
-// © 2016 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html
-/*
-*******************************************************************************
-* Copyright (C) 2009-2016, International Business Machines Corporation and
-* others. All Rights Reserved.
-*******************************************************************************
-*
-* This file contains the class DecimalFormatStaticSets
-*
-* DecimalFormatStaticSets holds the UnicodeSets that are needed for lenient
-* parsing of decimal and group separators.
-********************************************************************************
-*/
-
-#include "unicode/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/unistr.h"
-#include "unicode/uniset.h"
-#include "unicode/uchar.h"
-#include "cmemory.h"
-#include "cstring.h"
-#include "uassert.h"
-#include "ucln_in.h"
-#include "umutex.h"
-
-#include "decfmtst.h"
-
-U_NAMESPACE_BEGIN
-
-
-//------------------------------------------------------------------------------
-//
-// Unicode Set pattern strings for all of the required constant sets.
-// Initialized with hex values for portability to EBCDIC based machines.
-// Really ugly, but there's no good way to avoid it.
-//
-//------------------------------------------------------------------------------
-
-static const UChar gDotEquivalentsPattern[] = {
- // [ . \u2024 \u3002 \uFE12 \uFE52 \uFF0E \uFF61 ]
- 0x005B, 0x002E, 0x2024, 0x3002, 0xFE12, 0xFE52, 0xFF0E, 0xFF61, 0x005D, 0x0000};
-
-static const UChar gCommaEquivalentsPattern[] = {
- // [ , \u060C \u066B \u3001 \uFE10 \uFE11 \uFE50 \uFE51 \uFF0C \uFF64 ]
- 0x005B, 0x002C, 0x060C, 0x066B, 0x3001, 0xFE10, 0xFE11, 0xFE50, 0xFE51, 0xFF0C, 0xFF64, 0x005D, 0x0000};
-
-static const UChar gOtherGroupingSeparatorsPattern[] = {
- // [ \ SPACE ' NBSP \u066C \u2000 - \u200A \u2018 \u2019 \u202F \u205F \u3000 \uFF07 ]
- 0x005B, 0x005C, 0x0020, 0x0027, 0x00A0, 0x066C, 0x2000, 0x002D, 0x200A, 0x2018, 0x2019, 0x202F, 0x205F, 0x3000, 0xFF07, 0x005D, 0x0000};
-
-static const UChar gDashEquivalentsPattern[] = {
- // [ \ - HYPHEN F_DASH N_DASH MINUS ]
- 0x005B, 0x005C, 0x002D, 0x2010, 0x2012, 0x2013, 0x2212, 0x005D, 0x0000};
-
-static const UChar gStrictDotEquivalentsPattern[] = {
- // [ . \u2024 \uFE52 \uFF0E \uFF61 ]
- 0x005B, 0x002E, 0x2024, 0xFE52, 0xFF0E, 0xFF61, 0x005D, 0x0000};
-
-static const UChar gStrictCommaEquivalentsPattern[] = {
- // [ , \u066B \uFE10 \uFE50 \uFF0C ]
- 0x005B, 0x002C, 0x066B, 0xFE10, 0xFE50, 0xFF0C, 0x005D, 0x0000};
-
-static const UChar gStrictOtherGroupingSeparatorsPattern[] = {
- // [ \ SPACE ' NBSP \u066C \u2000 - \u200A \u2018 \u2019 \u202F \u205F \u3000 \uFF07 ]
- 0x005B, 0x005C, 0x0020, 0x0027, 0x00A0, 0x066C, 0x2000, 0x002D, 0x200A, 0x2018, 0x2019, 0x202F, 0x205F, 0x3000, 0xFF07, 0x005D, 0x0000};
-
-static const UChar gStrictDashEquivalentsPattern[] = {
- // [ \ - MINUS ]
- 0x005B, 0x005C, 0x002D, 0x2212, 0x005D, 0x0000};
-
-static const UChar32 gMinusSigns[] = {
- 0x002D,
- 0x207B,
- 0x208B,
- 0x2212,
- 0x2796,
- 0xFE63,
- 0xFF0D};
-
-static const UChar32 gPlusSigns[] = {
- 0x002B,
- 0x207A,
- 0x208A,
- 0x2795,
- 0xfB29,
- 0xFE62,
- 0xFF0B};
-
-static void initUnicodeSet(const UChar32 *raw, int32_t len, UnicodeSet *s) {
- for (int32_t i = 0; i < len; ++i) {
- s->add(raw[i]);
- }
-}
-
-DecimalFormatStaticSets::DecimalFormatStaticSets(UErrorCode &status)
-: fDotEquivalents(NULL),
- fCommaEquivalents(NULL),
- fOtherGroupingSeparators(NULL),
- fDashEquivalents(NULL),
- fStrictDotEquivalents(NULL),
- fStrictCommaEquivalents(NULL),
- fStrictOtherGroupingSeparators(NULL),
- fStrictDashEquivalents(NULL),
- fDefaultGroupingSeparators(NULL),
- fStrictDefaultGroupingSeparators(NULL),
- fMinusSigns(NULL),
- fPlusSigns(NULL)
-{
- fDotEquivalents = new UnicodeSet(UnicodeString(TRUE, gDotEquivalentsPattern, -1), status);
- fCommaEquivalents = new UnicodeSet(UnicodeString(TRUE, gCommaEquivalentsPattern, -1), status);
- fOtherGroupingSeparators = new UnicodeSet(UnicodeString(TRUE, gOtherGroupingSeparatorsPattern, -1), status);
- fDashEquivalents = new UnicodeSet(UnicodeString(TRUE, gDashEquivalentsPattern, -1), status);
-
- fStrictDotEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictDotEquivalentsPattern, -1), status);
- fStrictCommaEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictCommaEquivalentsPattern, -1), status);
- fStrictOtherGroupingSeparators = new UnicodeSet(UnicodeString(TRUE, gStrictOtherGroupingSeparatorsPattern, -1), status);
- fStrictDashEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictDashEquivalentsPattern, -1), status);
-
-
- fDefaultGroupingSeparators = new UnicodeSet(*fDotEquivalents);
- fDefaultGroupingSeparators->addAll(*fCommaEquivalents);
- fDefaultGroupingSeparators->addAll(*fOtherGroupingSeparators);
-
- fStrictDefaultGroupingSeparators = new UnicodeSet(*fStrictDotEquivalents);
- fStrictDefaultGroupingSeparators->addAll(*fStrictCommaEquivalents);
- fStrictDefaultGroupingSeparators->addAll(*fStrictOtherGroupingSeparators);
-
- fMinusSigns = new UnicodeSet();
- fPlusSigns = new UnicodeSet();
-
- // Check for null pointers
- if (fDotEquivalents == NULL || fCommaEquivalents == NULL || fOtherGroupingSeparators == NULL || fDashEquivalents == NULL ||
- fStrictDotEquivalents == NULL || fStrictCommaEquivalents == NULL || fStrictOtherGroupingSeparators == NULL || fStrictDashEquivalents == NULL ||
- fDefaultGroupingSeparators == NULL || fStrictOtherGroupingSeparators == NULL ||
- fMinusSigns == NULL || fPlusSigns == NULL) {
- cleanup();
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
-
- initUnicodeSet(
- gMinusSigns,
- UPRV_LENGTHOF(gMinusSigns),
- fMinusSigns);
- initUnicodeSet(
- gPlusSigns,
- UPRV_LENGTHOF(gPlusSigns),
- fPlusSigns);
-
- // Freeze all the sets
- fDotEquivalents->freeze();
- fCommaEquivalents->freeze();
- fOtherGroupingSeparators->freeze();
- fDashEquivalents->freeze();
- fStrictDotEquivalents->freeze();
- fStrictCommaEquivalents->freeze();
- fStrictOtherGroupingSeparators->freeze();
- fStrictDashEquivalents->freeze();
- fDefaultGroupingSeparators->freeze();
- fStrictDefaultGroupingSeparators->freeze();
- fMinusSigns->freeze();
- fPlusSigns->freeze();
-}
-
-DecimalFormatStaticSets::~DecimalFormatStaticSets() {
- cleanup();
-}
-
-void DecimalFormatStaticSets::cleanup() { // Be sure to clean up newly added fields!
- delete fDotEquivalents; fDotEquivalents = NULL;
- delete fCommaEquivalents; fCommaEquivalents = NULL;
- delete fOtherGroupingSeparators; fOtherGroupingSeparators = NULL;
- delete fDashEquivalents; fDashEquivalents = NULL;
- delete fStrictDotEquivalents; fStrictDotEquivalents = NULL;
- delete fStrictCommaEquivalents; fStrictCommaEquivalents = NULL;
- delete fStrictOtherGroupingSeparators; fStrictOtherGroupingSeparators = NULL;
- delete fStrictDashEquivalents; fStrictDashEquivalents = NULL;
- delete fDefaultGroupingSeparators; fDefaultGroupingSeparators = NULL;
- delete fStrictDefaultGroupingSeparators; fStrictDefaultGroupingSeparators = NULL;
- delete fStrictOtherGroupingSeparators; fStrictOtherGroupingSeparators = NULL;
- delete fMinusSigns; fMinusSigns = NULL;
- delete fPlusSigns; fPlusSigns = NULL;
-}
-
-static DecimalFormatStaticSets *gStaticSets;
-static icu::UInitOnce gStaticSetsInitOnce = U_INITONCE_INITIALIZER;
-
-
-//------------------------------------------------------------------------------
-//
-// decfmt_cleanup Memory cleanup function, free/delete all
-// cached memory. Called by ICU's u_cleanup() function.
-//
-//------------------------------------------------------------------------------
-U_CDECL_BEGIN
-static UBool U_CALLCONV
-decimfmt_cleanup(void)
-{
- delete gStaticSets;
- gStaticSets = NULL;
- gStaticSetsInitOnce.reset();
- return TRUE;
-}
-
-static void U_CALLCONV initSets(UErrorCode &status) {
- U_ASSERT(gStaticSets == NULL);
- ucln_i18n_registerCleanup(UCLN_I18N_DECFMT, decimfmt_cleanup);
- gStaticSets = new DecimalFormatStaticSets(status);
- if (U_FAILURE(status)) {
- delete gStaticSets;
- gStaticSets = NULL;
- return;
- }
- if (gStaticSets == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
-}
-U_CDECL_END
-
-const DecimalFormatStaticSets *DecimalFormatStaticSets::getStaticSets(UErrorCode &status) {
- umtx_initOnce(gStaticSetsInitOnce, initSets, status);
- return gStaticSets;
-}
-
-
-const UnicodeSet *DecimalFormatStaticSets::getSimilarDecimals(UChar32 decimal, UBool strictParse)
-{
- UErrorCode status = U_ZERO_ERROR;
- umtx_initOnce(gStaticSetsInitOnce, initSets, status);
- if (U_FAILURE(status)) {
- return NULL;
- }
-
- if (gStaticSets->fDotEquivalents->contains(decimal)) {
- return strictParse ? gStaticSets->fStrictDotEquivalents : gStaticSets->fDotEquivalents;
- }
-
- if (gStaticSets->fCommaEquivalents->contains(decimal)) {
- return strictParse ? gStaticSets->fStrictCommaEquivalents : gStaticSets->fCommaEquivalents;
- }
-
- // if there is no match, return NULL
- return NULL;
-}
-
-
-U_NAMESPACE_END
-#endif // !UCONFIG_NO_FORMATTING
diff --git a/deps/icu-small/source/i18n/decfmtst.h b/deps/icu-small/source/i18n/decfmtst.h
deleted file mode 100644
index 63ae50c6df904a..00000000000000
--- a/deps/icu-small/source/i18n/decfmtst.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// © 2016 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html
-/*
-*******************************************************************************
-* Copyright (C) 2009-2016, International Business Machines Corporation and
-* others. All Rights Reserved.
-*******************************************************************************
-*
-* This file contains declarations for the class DecimalFormatStaticSets
-*
-* DecimalFormatStaticSets holds the UnicodeSets that are needed for lenient
-* parsing of decimal and group separators.
-********************************************************************************
-*/
-
-#ifndef DECFMTST_H
-#define DECFMTST_H
-
-#include "unicode/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/uobject.h"
-
-U_NAMESPACE_BEGIN
-
-class UnicodeSet;
-
-
-class DecimalFormatStaticSets : public UMemory
-{
-public:
- // Constructor and Destructor not for general use.
- // Public to permit access from plain C implementation functions.
- DecimalFormatStaticSets(UErrorCode &status);
- ~DecimalFormatStaticSets();
-
- /**
- * Return a pointer to a lazy-initialized singleton instance of this class.
- */
- static const DecimalFormatStaticSets *getStaticSets(UErrorCode &status);
-
- static const UnicodeSet *getSimilarDecimals(UChar32 decimal, UBool strictParse);
-
- UnicodeSet *fDotEquivalents;
- UnicodeSet *fCommaEquivalents;
- UnicodeSet *fOtherGroupingSeparators;
- UnicodeSet *fDashEquivalents;
-
- UnicodeSet *fStrictDotEquivalents;
- UnicodeSet *fStrictCommaEquivalents;
- UnicodeSet *fStrictOtherGroupingSeparators;
- UnicodeSet *fStrictDashEquivalents;
-
- UnicodeSet *fDefaultGroupingSeparators;
- UnicodeSet *fStrictDefaultGroupingSeparators;
-
- UnicodeSet *fMinusSigns;
- UnicodeSet *fPlusSigns;
-private:
- void cleanup();
-
-};
-
-
-U_NAMESPACE_END
-
-#endif // !UCONFIG_NO_FORMATTING
-#endif // DECFMTST_H
diff --git a/deps/icu-small/source/i18n/decimalformatpattern.cpp b/deps/icu-small/source/i18n/decimalformatpattern.cpp
deleted file mode 100644
index 80a1870f33ef8d..00000000000000
--- a/deps/icu-small/source/i18n/decimalformatpattern.cpp
+++ /dev/null
@@ -1,656 +0,0 @@
-// © 2016 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html
-/*
-*******************************************************************************
-* Copyright (C) 1997-2015, International Business Machines Corporation and *
-* others. All Rights Reserved. *
-*******************************************************************************
-*/
-
-#include "uassert.h"
-#include "decimalformatpattern.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/dcfmtsym.h"
-#include "unicode/format.h"
-#include "unicode/utf16.h"
-#include "decimalformatpatternimpl.h"
-
-
-#ifdef FMT_DEBUG
-#define debug(x) printf("%s:%d: %s\n", __FILE__,__LINE__, x);
-#else
-#define debug(x)
-#endif
-
-U_NAMESPACE_BEGIN
-
-// TODO: Travis Keep: Copied from numfmt.cpp
-static int32_t kDoubleIntegerDigits = 309;
-static int32_t kDoubleFractionDigits = 340;
-
-
-// TODO: Travis Keep: Copied from numfmt.cpp
-static int32_t gDefaultMaxIntegerDigits = 2000000000;
-
-// TODO: Travis Keep: This function was copied from format.cpp
-static void syntaxError(const UnicodeString& pattern,
- int32_t pos,
- UParseError& parseError) {
- parseError.offset = pos;
- parseError.line=0; // we are not using line number
-
- // for pre-context
- int32_t start = (pos < U_PARSE_CONTEXT_LEN)? 0 : (pos - (U_PARSE_CONTEXT_LEN-1
- /* subtract 1 so that we have room for null*/));
- int32_t stop = pos;
- pattern.extract(start,stop-start,parseError.preContext,0);
- //null terminate the buffer
- parseError.preContext[stop-start] = 0;
-
- //for post-context
- start = pattern.moveIndex32(pos, 1);
- stop = pos + U_PARSE_CONTEXT_LEN - 1;
- if (stop > pattern.length()) {
- stop = pattern.length();
- }
- pattern.extract(start, stop - start, parseError.postContext, 0);
- //null terminate the buffer
- parseError.postContext[stop-start]= 0;
-}
-
-DecimalFormatPattern::DecimalFormatPattern()
- : fMinimumIntegerDigits(1),
- fMaximumIntegerDigits(gDefaultMaxIntegerDigits),
- fMinimumFractionDigits(0),
- fMaximumFractionDigits(3),
- fUseSignificantDigits(FALSE),
- fMinimumSignificantDigits(1),
- fMaximumSignificantDigits(6),
- fUseExponentialNotation(FALSE),
- fMinExponentDigits(0),
- fExponentSignAlwaysShown(FALSE),
- fCurrencySignCount(fgCurrencySignCountZero),
- fGroupingUsed(TRUE),
- fGroupingSize(0),
- fGroupingSize2(0),
- fMultiplier(1),
- fDecimalSeparatorAlwaysShown(FALSE),
- fFormatWidth(0),
- fRoundingIncrementUsed(FALSE),
- fRoundingIncrement(),
- fPad(kDefaultPad),
- fNegPatternsBogus(TRUE),
- fPosPatternsBogus(TRUE),
- fNegPrefixPattern(),
- fNegSuffixPattern(),
- fPosPrefixPattern(),
- fPosSuffixPattern(),
- fPadPosition(DecimalFormatPattern::kPadBeforePrefix) {
-}
-
-
-DecimalFormatPatternParser::DecimalFormatPatternParser() :
- fZeroDigit(kPatternZeroDigit),
- fSigDigit(kPatternSignificantDigit),
- fGroupingSeparator((UChar)kPatternGroupingSeparator),
- fDecimalSeparator((UChar)kPatternDecimalSeparator),
- fPercent((UChar)kPatternPercent),
- fPerMill((UChar)kPatternPerMill),
- fDigit((UChar)kPatternDigit),
- fSeparator((UChar)kPatternSeparator),
- fExponent((UChar)kPatternExponent),
- fPlus((UChar)kPatternPlus),
- fMinus((UChar)kPatternMinus),
- fPadEscape((UChar)kPatternPadEscape) {
-}
-
-void DecimalFormatPatternParser::useSymbols(
- const DecimalFormatSymbols& symbols) {
- fZeroDigit = symbols.getConstSymbol(
- DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
- fSigDigit = symbols.getConstSymbol(
- DecimalFormatSymbols::kSignificantDigitSymbol).char32At(0);
- fGroupingSeparator = symbols.getConstSymbol(
- DecimalFormatSymbols::kGroupingSeparatorSymbol);
- fDecimalSeparator = symbols.getConstSymbol(
- DecimalFormatSymbols::kDecimalSeparatorSymbol);
- fPercent = symbols.getConstSymbol(
- DecimalFormatSymbols::kPercentSymbol);
- fPerMill = symbols.getConstSymbol(
- DecimalFormatSymbols::kPerMillSymbol);
- fDigit = symbols.getConstSymbol(
- DecimalFormatSymbols::kDigitSymbol);
- fSeparator = symbols.getConstSymbol(
- DecimalFormatSymbols::kPatternSeparatorSymbol);
- fExponent = symbols.getConstSymbol(
- DecimalFormatSymbols::kExponentialSymbol);
- fPlus = symbols.getConstSymbol(
- DecimalFormatSymbols::kPlusSignSymbol);
- fMinus = symbols.getConstSymbol(
- DecimalFormatSymbols::kMinusSignSymbol);
- fPadEscape = symbols.getConstSymbol(
- DecimalFormatSymbols::kPadEscapeSymbol);
-}
-
-void
-DecimalFormatPatternParser::applyPatternWithoutExpandAffix(
- const UnicodeString& pattern,
- DecimalFormatPattern& out,
- UParseError& parseError,
- UErrorCode& status) {
- if (U_FAILURE(status))
- {
- return;
- }
- out = DecimalFormatPattern();
-
- // Clear error struct
- parseError.offset = -1;
- parseError.preContext[0] = parseError.postContext[0] = (UChar)0;
-
- // TODO: Travis Keep: This won't always work.
- UChar nineDigit = (UChar)(fZeroDigit + 9);
- int32_t digitLen = fDigit.length();
- int32_t groupSepLen = fGroupingSeparator.length();
- int32_t decimalSepLen = fDecimalSeparator.length();
-
- int32_t pos = 0;
- int32_t patLen = pattern.length();
- // Part 0 is the positive pattern. Part 1, if present, is the negative
- // pattern.
- for (int32_t part=0; part<2 && pos 0 || sigDigitCount > 0) {
- ++digitRightCount;
- } else {
- ++digitLeftCount;
- }
- if (groupingCount >= 0 && decimalPos < 0) {
- ++groupingCount;
- }
- pos += digitLen;
- } else if ((ch >= fZeroDigit && ch <= nineDigit) ||
- ch == fSigDigit) {
- if (digitRightCount > 0) {
- // Unexpected '0'
- debug("Unexpected '0'")
- status = U_UNEXPECTED_TOKEN;
- syntaxError(pattern,pos,parseError);
- return;
- }
- if (ch == fSigDigit) {
- ++sigDigitCount;
- } else {
- if (ch != fZeroDigit && roundingPos < 0) {
- roundingPos = digitLeftCount + zeroDigitCount;
- }
- if (roundingPos >= 0) {
- roundingInc.append((char)(ch - fZeroDigit + '0'));
- }
- ++zeroDigitCount;
- }
- if (groupingCount >= 0 && decimalPos < 0) {
- ++groupingCount;
- }
- pos += U16_LENGTH(ch);
- } else if (pattern.compare(pos, groupSepLen, fGroupingSeparator) == 0) {
- if (decimalPos >= 0) {
- // Grouping separator after decimal
- debug("Grouping separator after decimal")
- status = U_UNEXPECTED_TOKEN;
- syntaxError(pattern,pos,parseError);
- return;
- }
- groupingCount2 = groupingCount;
- groupingCount = 0;
- pos += groupSepLen;
- } else if (pattern.compare(pos, decimalSepLen, fDecimalSeparator) == 0) {
- if (decimalPos >= 0) {
- // Multiple decimal separators
- debug("Multiple decimal separators")
- status = U_MULTIPLE_DECIMAL_SEPARATORS;
- syntaxError(pattern,pos,parseError);
- return;
- }
- // Intentionally incorporate the digitRightCount,
- // even though it is illegal for this to be > 0
- // at this point. We check pattern syntax below.
- decimalPos = digitLeftCount + zeroDigitCount + digitRightCount;
- pos += decimalSepLen;
- } else {
- if (pattern.compare(pos, fExponent.length(), fExponent) == 0) {
- if (expDigits >= 0) {
- // Multiple exponential symbols
- debug("Multiple exponential symbols")
- status = U_MULTIPLE_EXPONENTIAL_SYMBOLS;
- syntaxError(pattern,pos,parseError);
- return;
- }
- if (groupingCount >= 0) {
- // Grouping separator in exponential pattern
- debug("Grouping separator in exponential pattern")
- status = U_MALFORMED_EXPONENTIAL_PATTERN;
- syntaxError(pattern,pos,parseError);
- return;
- }
- pos += fExponent.length();
- // Check for positive prefix
- if (pos < patLen
- && pattern.compare(pos, fPlus.length(), fPlus) == 0) {
- expSignAlways = TRUE;
- pos += fPlus.length();
- }
- // Use lookahead to parse out the exponential part of the
- // pattern, then jump into suffix subpart.
- expDigits = 0;
- while (pos < patLen &&
- pattern.char32At(pos) == fZeroDigit) {
- ++expDigits;
- pos += U16_LENGTH(fZeroDigit);
- }
-
- // 1. Require at least one mantissa pattern digit
- // 2. Disallow "#+ @" in mantissa
- // 3. Require at least one exponent pattern digit
- if (((digitLeftCount + zeroDigitCount) < 1 &&
- (sigDigitCount + digitRightCount) < 1) ||
- (sigDigitCount > 0 && digitLeftCount > 0) ||
- expDigits < 1) {
- // Malformed exponential pattern
- debug("Malformed exponential pattern")
- status = U_MALFORMED_EXPONENTIAL_PATTERN;
- syntaxError(pattern,pos,parseError);
- return;
- }
- }
- // Transition to suffix subpart
- subpart = 2; // suffix subpart
- affix = &suffix;
- sub0Limit = pos;
- continue;
- }
- break;
- case 1: // Prefix subpart
- case 2: // Suffix subpart
- // Process the prefix / suffix characters
- // Process unquoted characters seen in prefix or suffix
- // subpart.
-
- // Several syntax characters implicitly begins the
- // next subpart if we are in the prefix; otherwise
- // they are illegal if unquoted.
- if (!pattern.compare(pos, digitLen, fDigit) ||
- !pattern.compare(pos, groupSepLen, fGroupingSeparator) ||
- !pattern.compare(pos, decimalSepLen, fDecimalSeparator) ||
- (ch >= fZeroDigit && ch <= nineDigit) ||
- ch == fSigDigit) {
- if (subpart == 1) { // prefix subpart
- subpart = 0; // pattern proper subpart
- sub0Start = pos; // Reprocess this character
- continue;
- } else {
- status = U_UNQUOTED_SPECIAL;
- syntaxError(pattern,pos,parseError);
- return;
- }
- } else if (ch == kCurrencySign) {
- affix->append(kQuote); // Encode currency
- // Use lookahead to determine if the currency sign is
- // doubled or not.
- U_ASSERT(U16_LENGTH(kCurrencySign) == 1);
- if ((pos+1) < pattern.length() && pattern[pos+1] == kCurrencySign) {
- affix->append(kCurrencySign);
- ++pos; // Skip over the doubled character
- if ((pos+1) < pattern.length() &&
- pattern[pos+1] == kCurrencySign) {
- affix->append(kCurrencySign);
- ++pos; // Skip over the doubled character
- out.fCurrencySignCount = fgCurrencySignCountInPluralFormat;
- } else {
- out.fCurrencySignCount = fgCurrencySignCountInISOFormat;
- }
- } else {
- out.fCurrencySignCount = fgCurrencySignCountInSymbolFormat;
- }
- // Fall through to append(ch)
- } else if (ch == kQuote) {
- // A quote outside quotes indicates either the opening
- // quote or two quotes, which is a quote literal. That is,
- // we have the first quote in 'do' or o''clock.
- U_ASSERT(U16_LENGTH(kQuote) == 1);
- ++pos;
- if (pos < pattern.length() && pattern[pos] == kQuote) {
- affix->append(kQuote); // Encode quote
- // Fall through to append(ch)
- } else {
- subpart += 2; // open quote
- continue;
- }
- } else if (pattern.compare(pos, fSeparator.length(), fSeparator) == 0) {
- // Don't allow separators in the prefix, and don't allow
- // separators in the second pattern (part == 1).
- if (subpart == 1 || part == 1) {
- // Unexpected separator
- debug("Unexpected separator")
- status = U_UNEXPECTED_TOKEN;
- syntaxError(pattern,pos,parseError);
- return;
- }
- sub2Limit = pos;
- isPartDone = TRUE; // Go to next part
- pos += fSeparator.length();
- break;
- } else if (pattern.compare(pos, fPercent.length(), fPercent) == 0) {
- // Next handle characters which are appended directly.
- if (multiplier != 1) {
- // Too many percent/perMill characters
- debug("Too many percent characters")
- status = U_MULTIPLE_PERCENT_SYMBOLS;
- syntaxError(pattern,pos,parseError);
- return;
- }
- affix->append(kQuote); // Encode percent/perMill
- affix->append(kPatternPercent); // Use unlocalized pattern char
- multiplier = 100;
- pos += fPercent.length();
- break;
- } else if (pattern.compare(pos, fPerMill.length(), fPerMill) == 0) {
- // Next handle characters which are appended directly.
- if (multiplier != 1) {
- // Too many percent/perMill characters
- debug("Too many perMill characters")
- status = U_MULTIPLE_PERMILL_SYMBOLS;
- syntaxError(pattern,pos,parseError);
- return;
- }
- affix->append(kQuote); // Encode percent/perMill
- affix->append(kPatternPerMill); // Use unlocalized pattern char
- multiplier = 1000;
- pos += fPerMill.length();
- break;
- } else if (pattern.compare(pos, fPadEscape.length(), fPadEscape) == 0) {
- if (padPos >= 0 || // Multiple pad specifiers
- (pos+1) == pattern.length()) { // Nothing after padEscape
- debug("Multiple pad specifiers")
- status = U_MULTIPLE_PAD_SPECIFIERS;
- syntaxError(pattern,pos,parseError);
- return;
- }
- padPos = pos;
- pos += fPadEscape.length();
- padChar = pattern.char32At(pos);
- pos += U16_LENGTH(padChar);
- break;
- } else if (pattern.compare(pos, fMinus.length(), fMinus) == 0) {
- affix->append(kQuote); // Encode minus
- affix->append(kPatternMinus);
- pos += fMinus.length();
- break;
- } else if (pattern.compare(pos, fPlus.length(), fPlus) == 0) {
- affix->append(kQuote); // Encode plus
- affix->append(kPatternPlus);
- pos += fPlus.length();
- break;
- }
- // Unquoted, non-special characters fall through to here, as
- // well as other code which needs to append something to the
- // affix.
- affix->append(ch);
- pos += U16_LENGTH(ch);
- break;
- case 3: // Prefix subpart, in quote
- case 4: // Suffix subpart, in quote
- // A quote within quotes indicates either the closing
- // quote or two quotes, which is a quote literal. That is,
- // we have the second quote in 'do' or 'don''t'.
- if (ch == kQuote) {
- ++pos;
- if (pos < pattern.length() && pattern[pos] == kQuote) {
- affix->append(kQuote); // Encode quote
- // Fall through to append(ch)
- } else {
- subpart -= 2; // close quote
- continue;
- }
- }
- affix->append(ch);
- pos += U16_LENGTH(ch);
- break;
- }
- }
-
- if (sub0Limit == 0) {
- sub0Limit = pattern.length();
- }
-
- if (sub2Limit == 0) {
- sub2Limit = pattern.length();
- }
-
- /* Handle patterns with no '0' pattern character. These patterns
- * are legal, but must be recodified to make sense. "##.###" ->
- * "#0.###". ".###" -> ".0##".
- *
- * We allow patterns of the form "####" to produce a zeroDigitCount
- * of zero (got that?); although this seems like it might make it
- * possible for format() to produce empty strings, format() checks
- * for this condition and outputs a zero digit in this situation.
- * Having a zeroDigitCount of zero yields a minimum integer digits
- * of zero, which allows proper round-trip patterns. We don't want
- * "#" to become "#0" when toPattern() is called (even though that's
- * what it really is, semantically).
- */
- if (zeroDigitCount == 0 && sigDigitCount == 0 &&
- digitLeftCount > 0 && decimalPos >= 0) {
- // Handle "###.###" and "###." and ".###"
- int n = decimalPos;
- if (n == 0)
- ++n; // Handle ".###"
- digitRightCount = digitLeftCount - n;
- digitLeftCount = n - 1;
- zeroDigitCount = 1;
- }
-
- // Do syntax checking on the digits, decimal points, and quotes.
- if ((decimalPos < 0 && digitRightCount > 0 && sigDigitCount == 0) ||
- (decimalPos >= 0 &&
- (sigDigitCount > 0 ||
- decimalPos < digitLeftCount ||
- decimalPos > (digitLeftCount + zeroDigitCount))) ||
- groupingCount == 0 || groupingCount2 == 0 ||
- (sigDigitCount > 0 && zeroDigitCount > 0) ||
- subpart > 2)
- { // subpart > 2 == unmatched quote
- debug("Syntax error")
- status = U_PATTERN_SYNTAX_ERROR;
- syntaxError(pattern,pos,parseError);
- return;
- }
-
- // Make sure pad is at legal position before or after affix.
- if (padPos >= 0) {
- if (padPos == start) {
- padPos = DecimalFormatPattern::kPadBeforePrefix;
- } else if (padPos+2 == sub0Start) {
- padPos = DecimalFormatPattern::kPadAfterPrefix;
- } else if (padPos == sub0Limit) {
- padPos = DecimalFormatPattern::kPadBeforeSuffix;
- } else if (padPos+2 == sub2Limit) {
- padPos = DecimalFormatPattern::kPadAfterSuffix;
- } else {
- // Illegal pad position
- debug("Illegal pad position")
- status = U_ILLEGAL_PAD_POSITION;
- syntaxError(pattern,pos,parseError);
- return;
- }
- }
-
- if (part == 0) {
- out.fPosPatternsBogus = FALSE;
- out.fPosPrefixPattern = prefix;
- out.fPosSuffixPattern = suffix;
- out.fNegPatternsBogus = TRUE;
- out.fNegPrefixPattern.remove();
- out.fNegSuffixPattern.remove();
-
- out.fUseExponentialNotation = (expDigits >= 0);
- if (out.fUseExponentialNotation) {
- out.fMinExponentDigits = expDigits;
- }
- out.fExponentSignAlwaysShown = expSignAlways;
- int32_t digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount;
- // The effectiveDecimalPos is the position the decimal is at or
- // would be at if there is no decimal. Note that if
- // decimalPos<0, then digitTotalCount == digitLeftCount +
- // zeroDigitCount.
- int32_t effectiveDecimalPos = decimalPos >= 0 ? decimalPos : digitTotalCount;
- UBool isSigDig = (sigDigitCount > 0);
- out.fUseSignificantDigits = isSigDig;
- if (isSigDig) {
- out.fMinimumSignificantDigits = sigDigitCount;
- out.fMaximumSignificantDigits = sigDigitCount + digitRightCount;
- } else {
- int32_t minInt = effectiveDecimalPos - digitLeftCount;
- out.fMinimumIntegerDigits = minInt;
- out.fMaximumIntegerDigits = out.fUseExponentialNotation
- ? digitLeftCount + out.fMinimumIntegerDigits
- : gDefaultMaxIntegerDigits;
- out.fMaximumFractionDigits = decimalPos >= 0
- ? (digitTotalCount - decimalPos) : 0;
- out.fMinimumFractionDigits = decimalPos >= 0
- ? (digitLeftCount + zeroDigitCount - decimalPos) : 0;
- }
- out.fGroupingUsed = groupingCount > 0;
- out.fGroupingSize = (groupingCount > 0) ? groupingCount : 0;
- out.fGroupingSize2 = (groupingCount2 > 0 && groupingCount2 != groupingCount)
- ? groupingCount2 : 0;
- out.fMultiplier = multiplier;
- out.fDecimalSeparatorAlwaysShown = decimalPos == 0
- || decimalPos == digitTotalCount;
- if (padPos >= 0) {
- out.fPadPosition = (DecimalFormatPattern::EPadPosition) padPos;
- // To compute the format width, first set up sub0Limit -
- // sub0Start. Add in prefix/suffix length later.
-
- // fFormatWidth = prefix.length() + suffix.length() +
- // sub0Limit - sub0Start;
- out.fFormatWidth = sub0Limit - sub0Start;
- out.fPad = padChar;
- } else {
- out.fFormatWidth = 0;
- }
- if (roundingPos >= 0) {
- out.fRoundingIncrementUsed = TRUE;
- roundingInc.setDecimalAt(effectiveDecimalPos - roundingPos);
- out.fRoundingIncrement = roundingInc;
- } else {
- out.fRoundingIncrementUsed = FALSE;
- }
- } else {
- out.fNegPatternsBogus = FALSE;
- out.fNegPrefixPattern = prefix;
- out.fNegSuffixPattern = suffix;
- }
- }
-
- if (pattern.length() == 0) {
- out.fNegPatternsBogus = TRUE;
- out.fNegPrefixPattern.remove();
- out.fNegSuffixPattern.remove();
- out.fPosPatternsBogus = FALSE;
- out.fPosPrefixPattern.remove();
- out.fPosSuffixPattern.remove();
-
- out.fMinimumIntegerDigits = 0;
- out.fMaximumIntegerDigits = kDoubleIntegerDigits;
- out.fMinimumFractionDigits = 0;
- out.fMaximumFractionDigits = kDoubleFractionDigits;
-
- out.fUseExponentialNotation = FALSE;
- out.fCurrencySignCount = fgCurrencySignCountZero;
- out.fGroupingUsed = FALSE;
- out.fGroupingSize = 0;
- out.fGroupingSize2 = 0;
- out.fMultiplier = 1;
- out.fDecimalSeparatorAlwaysShown = FALSE;
- out.fFormatWidth = 0;
- out.fRoundingIncrementUsed = FALSE;
- }
-
- // If there was no negative pattern, or if the negative pattern is
- // identical to the positive pattern, then prepend the minus sign to the
- // positive pattern to form the negative pattern.
- if (out.fNegPatternsBogus ||
- (out.fNegPrefixPattern == out.fPosPrefixPattern
- && out.fNegSuffixPattern == out.fPosSuffixPattern)) {
- out.fNegPatternsBogus = FALSE;
- out.fNegSuffixPattern = out.fPosSuffixPattern;
- out.fNegPrefixPattern.remove();
- out.fNegPrefixPattern.append(kQuote).append(kPatternMinus)
- .append(out.fPosPrefixPattern);
- }
- // TODO: Deprecate/Remove out.fNegSuffixPattern and 3 other fields.
- AffixPattern::parseAffixString(
- out.fNegSuffixPattern, out.fNegSuffixAffix, status);
- AffixPattern::parseAffixString(
- out.fPosSuffixPattern, out.fPosSuffixAffix, status);
- AffixPattern::parseAffixString(
- out.fNegPrefixPattern, out.fNegPrefixAffix, status);
- AffixPattern::parseAffixString(
- out.fPosPrefixPattern, out.fPosPrefixAffix, status);
-}
-
-U_NAMESPACE_END
-
-#endif /* !UCONFIG_NO_FORMATTING */
diff --git a/deps/icu-small/source/i18n/decimalformatpattern.h b/deps/icu-small/source/i18n/decimalformatpattern.h
deleted file mode 100644
index 1c297575ead1e7..00000000000000
--- a/deps/icu-small/source/i18n/decimalformatpattern.h
+++ /dev/null
@@ -1,106 +0,0 @@
-// © 2016 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html
-/*
-*******************************************************************************
-* Copyright (C) 1997-2015, International Business Machines Corporation and *
-* others. All Rights Reserved. *
-*******************************************************************************
-*/
-#ifndef _DECIMAL_FORMAT_PATTERN
-#define _DECIMAL_FORMAT_PATTERN
-
-#include "unicode/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/uobject.h"
-#include "unicode/unistr.h"
-#include "digitlst.h"
-#include "affixpatternparser.h"
-
-U_NAMESPACE_BEGIN
-
-// currency sign count
-enum CurrencySignCount {
- fgCurrencySignCountZero,
- fgCurrencySignCountInSymbolFormat,
- fgCurrencySignCountInISOFormat,
- fgCurrencySignCountInPluralFormat
-};
-
-class DecimalFormatSymbols;
-
-struct DecimalFormatPattern : public UMemory {
- enum EPadPosition {
- kPadBeforePrefix,
- kPadAfterPrefix,
- kPadBeforeSuffix,
- kPadAfterSuffix
- };
-
- DecimalFormatPattern();
-
- int32_t fMinimumIntegerDigits;
- int32_t fMaximumIntegerDigits;
- int32_t fMinimumFractionDigits;
- int32_t fMaximumFractionDigits;
- UBool fUseSignificantDigits;
- int32_t fMinimumSignificantDigits;
- int32_t fMaximumSignificantDigits;
- UBool fUseExponentialNotation;
- int32_t fMinExponentDigits;
- UBool fExponentSignAlwaysShown;
- int32_t fCurrencySignCount;
- UBool fGroupingUsed;
- int32_t fGroupingSize;
- int32_t fGroupingSize2;
- int32_t fMultiplier;
- UBool fDecimalSeparatorAlwaysShown;
- int32_t fFormatWidth;
- UBool fRoundingIncrementUsed;
- DigitList fRoundingIncrement;
- UChar32 fPad;
- UBool fNegPatternsBogus;
- UBool fPosPatternsBogus;
- UnicodeString fNegPrefixPattern;
- UnicodeString fNegSuffixPattern;
- UnicodeString fPosPrefixPattern;
- UnicodeString fPosSuffixPattern;
- AffixPattern fNegPrefixAffix;
- AffixPattern fNegSuffixAffix;
- AffixPattern fPosPrefixAffix;
- AffixPattern fPosSuffixAffix;
- EPadPosition fPadPosition;
-};
-
-class DecimalFormatPatternParser : public UMemory {
- public:
- DecimalFormatPatternParser();
- void useSymbols(const DecimalFormatSymbols& symbols);
-
- void applyPatternWithoutExpandAffix(
- const UnicodeString& pattern,
- DecimalFormatPattern& out,
- UParseError& parseError,
- UErrorCode& status);
- private:
- DecimalFormatPatternParser(const DecimalFormatPatternParser&);
- DecimalFormatPatternParser& operator=(DecimalFormatPatternParser& rhs);
- UChar32 fZeroDigit;
- UChar32 fSigDigit;
- UnicodeString fGroupingSeparator;
- UnicodeString fDecimalSeparator;
- UnicodeString fPercent;
- UnicodeString fPerMill;
- UnicodeString fDigit;
- UnicodeString fSeparator;
- UnicodeString fExponent;
- UnicodeString fPlus;
- UnicodeString fMinus;
- UnicodeString fPadEscape;
-};
-
-U_NAMESPACE_END
-
-#endif /* !UCONFIG_NO_FORMATTING */
-#endif
diff --git a/deps/icu-small/source/i18n/decimalformatpatternimpl.h b/deps/icu-small/source/i18n/decimalformatpatternimpl.h
deleted file mode 100644
index 8cecc8cca02c72..00000000000000
--- a/deps/icu-small/source/i18n/decimalformatpatternimpl.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// © 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 decimalformatpatternimpl.h
-********************************************************************************
-*/
-
-#ifndef DECIMALFORMATPATTERNIMPL_H
-#define DECIMALFORMATPATTERNIMPL_H
-
-#include "unicode/utypes.h"
-
-#define kPatternZeroDigit ((UChar)0x0030) /*'0'*/
-#define kPatternSignificantDigit ((UChar)0x0040) /*'@'*/
-#define kPatternGroupingSeparator ((UChar)0x002C) /*','*/
-#define kPatternDecimalSeparator ((UChar)0x002E) /*'.'*/
-#define kPatternPerMill ((UChar)0x2030)
-#define kPatternPercent ((UChar)0x0025) /*'%'*/
-#define kPatternDigit ((UChar)0x0023) /*'#'*/
-#define kPatternSeparator ((UChar)0x003B) /*';'*/
-#define kPatternExponent ((UChar)0x0045) /*'E'*/
-#define kPatternPlus ((UChar)0x002B) /*'+'*/
-#define kPatternMinus ((UChar)0x002D) /*'-'*/
-#define kPatternPadEscape ((UChar)0x002A) /*'*'*/
-#define kQuote ((UChar)0x0027) /*'\''*/
-
-#define kCurrencySign ((UChar)0x00A4)
-#define kDefaultPad ((UChar)0x0020) /* */
-
-#endif
diff --git a/deps/icu-small/source/i18n/decimfmt.cpp b/deps/icu-small/source/i18n/decimfmt.cpp
index 80a9446e146f6c..a2638bb74298e3 100644
--- a/deps/icu-small/source/i18n/decimfmt.cpp
+++ b/deps/icu-small/source/i18n/decimfmt.cpp
@@ -1,3295 +1,1383 @@
-// © 2016 and later: Unicode, Inc. and others.
+// © 2018 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
-/*
-*******************************************************************************
-* Copyright (C) 1997-2015, International Business Machines Corporation and *
-* others. All Rights Reserved. *
-*******************************************************************************
-*
-* File DECIMFMT.CPP
-*
-* Modification History:
-*
-* Date Name Description
-* 02/19/97 aliu Converted from java.
-* 03/20/97 clhuang Implemented with new APIs.
-* 03/31/97 aliu Moved isLONG_MIN to DigitList, and fixed it.
-* 04/3/97 aliu Rewrote parsing and formatting completely, and
-* cleaned up and debugged. Actually works now.
-* Implemented NAN and INF handling, for both parsing
-* and formatting. Extensive testing & debugging.
-* 04/10/97 aliu Modified to compile on AIX.
-* 04/16/97 aliu Rewrote to use DigitList, which has been resurrected.
-* Changed DigitCount to int per code review.
-* 07/09/97 helena Made ParsePosition into a class.
-* 08/26/97 aliu Extensive changes to applyPattern; completely
-* rewritten from the Java.
-* 09/09/97 aliu Ported over support for exponential formats.
-* 07/20/98 stephen JDK 1.2 sync up.
-* Various instances of '0' replaced with 'NULL'
-* Check for grouping size in subFormat()
-* Brought subParse() in line with Java 1.2
-* Added method appendAffix()
-* 08/24/1998 srl Removed Mutex calls. This is not a thread safe class!
-* 02/22/99 stephen Removed character literals for EBCDIC safety
-* 06/24/99 helena Integrated Alan's NF enhancements and Java2 bug fixes
-* 06/28/99 stephen Fixed bugs in toPattern().
-* 06/29/99 stephen Fixed operator= to copy fFormatWidth, fPad,
-* fPadPosition
-********************************************************************************
-*/
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
-#include "unicode/uniset.h"
-#include "unicode/currpinf.h"
-#include "unicode/plurrule.h"
-#include "unicode/utf16.h"
-#include "unicode/numsys.h"
-#include "unicode/localpointer.h"
-#include "unicode/ustring.h"
-#include "uresimp.h"
-#include "ucurrimp.h"
-#include "charstr.h"
-#include "patternprops.h"
-#include "cstring.h"
-#include "uassert.h"
-#include "hash.h"
-#include "decfmtst.h"
-#include "plurrule_impl.h"
-#include "decimalformatpattern.h"
-#include "fmtableimp.h"
-#include "decimfmtimpl.h"
-#include "visibledigits.h"
-
-/*
- * On certain platforms, round is a macro defined in math.h
- * This undefine is to avoid conflict between the macro and
- * the function defined below.
- */
-#ifdef round
-#undef round
-#endif
-
-
-U_NAMESPACE_BEGIN
-
-#ifdef FMT_DEBUG
-#include
-static void _debugout(const char *f, int l, const UnicodeString& s) {
- char buf[2000];
- s.extract((int32_t) 0, s.length(), buf, "utf-8");
- printf("%s:%d: %s\n", f,l, buf);
-}
-#define debugout(x) _debugout(__FILE__,__LINE__,x)
-#define debug(x) printf("%s:%d: %s\n", __FILE__,__LINE__, x);
-static const UnicodeString dbg_null("","");
-#define DEREFSTR(x) ((x!=NULL)?(*x):(dbg_null))
+// Allow implicit conversion from char16_t* to UnicodeString for this file:
+// Helpful in toString methods and elsewhere.
+#define UNISTR_FROM_STRING_EXPLICIT
+
+#include
+#include
+#include
+#include "unicode/errorcode.h"
+#include "unicode/decimfmt.h"
+#include "number_decimalquantity.h"
+#include "number_types.h"
+#include "numparse_impl.h"
+#include "number_mapper.h"
+#include "number_patternstring.h"
+#include "putilimp.h"
+#include "number_utils.h"
+#include "number_utypes.h"
+
+using namespace icu;
+using namespace icu::number;
+using namespace icu::number::impl;
+using namespace icu::numparse;
+using namespace icu::numparse::impl;
+using ERoundingMode = icu::DecimalFormat::ERoundingMode;
+using EPadPosition = icu::DecimalFormat::EPadPosition;
+
+// MSVC warns C4805 when comparing bool with UBool
+// TODO: Move this macro into a better place?
+#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
+#define UBOOL_TO_BOOL(b) static_cast(b)
#else
-#define debugout(x)
-#define debug(x)
-#endif
-
-
-/* For currency parsing purose,
- * Need to remember all prefix patterns and suffix patterns of
- * every currency format pattern,
- * including the pattern of default currecny style
- * and plural currency style. And the patterns are set through applyPattern.
- */
-struct AffixPatternsForCurrency : public UMemory {
- // negative prefix pattern
- UnicodeString negPrefixPatternForCurrency;
- // negative suffix pattern
- UnicodeString negSuffixPatternForCurrency;
- // positive prefix pattern
- UnicodeString posPrefixPatternForCurrency;
- // positive suffix pattern
- UnicodeString posSuffixPatternForCurrency;
- int8_t patternType;
-
- AffixPatternsForCurrency(const UnicodeString& negPrefix,
- const UnicodeString& negSuffix,
- const UnicodeString& posPrefix,
- const UnicodeString& posSuffix,
- int8_t type) {
- negPrefixPatternForCurrency = negPrefix;
- negSuffixPatternForCurrency = negSuffix;
- posPrefixPatternForCurrency = posPrefix;
- posSuffixPatternForCurrency = posSuffix;
- patternType = type;
- }
-#ifdef FMT_DEBUG
- void dump() const {
- debugout( UnicodeString("AffixPatternsForCurrency( -=\"") +
- negPrefixPatternForCurrency + (UnicodeString)"\"/\"" +
- negSuffixPatternForCurrency + (UnicodeString)"\" +=\"" +
- posPrefixPatternForCurrency + (UnicodeString)"\"/\"" +
- posSuffixPatternForCurrency + (UnicodeString)"\" )");
- }
+#define UBOOL_TO_BOOL(b) b
#endif
-};
-
-/* affix for currency formatting when the currency sign in the pattern
- * equals to 3, such as the pattern contains 3 currency sign or
- * the formatter style is currency plural format style.
- */
-struct AffixesForCurrency : public UMemory {
- // negative prefix
- UnicodeString negPrefixForCurrency;
- // negative suffix
- UnicodeString negSuffixForCurrency;
- // positive prefix
- UnicodeString posPrefixForCurrency;
- // positive suffix
- UnicodeString posSuffixForCurrency;
-
- int32_t formatWidth;
-
- AffixesForCurrency(const UnicodeString& negPrefix,
- const UnicodeString& negSuffix,
- const UnicodeString& posPrefix,
- const UnicodeString& posSuffix) {
- negPrefixForCurrency = negPrefix;
- negSuffixForCurrency = negSuffix;
- posPrefixForCurrency = posPrefix;
- posSuffixForCurrency = posSuffix;
- }
-#ifdef FMT_DEBUG
- void dump() const {
- debugout( UnicodeString("AffixesForCurrency( -=\"") +
- negPrefixForCurrency + (UnicodeString)"\"/\"" +
- negSuffixForCurrency + (UnicodeString)"\" +=\"" +
- posPrefixForCurrency + (UnicodeString)"\"/\"" +
- posSuffixForCurrency + (UnicodeString)"\" )");
- }
-#endif
-};
-
-U_CDECL_BEGIN
-
-/**
- * @internal ICU 4.2
- */
-static UBool U_CALLCONV decimfmtAffixPatternValueComparator(UHashTok val1, UHashTok val2);
-
-
-static UBool
-U_CALLCONV decimfmtAffixPatternValueComparator(UHashTok val1, UHashTok val2) {
- const AffixPatternsForCurrency* affix_1 =
- (AffixPatternsForCurrency*)val1.pointer;
- const AffixPatternsForCurrency* affix_2 =
- (AffixPatternsForCurrency*)val2.pointer;
- return affix_1->negPrefixPatternForCurrency ==
- affix_2->negPrefixPatternForCurrency &&
- affix_1->negSuffixPatternForCurrency ==
- affix_2->negSuffixPatternForCurrency &&
- affix_1->posPrefixPatternForCurrency ==
- affix_2->posPrefixPatternForCurrency &&
- affix_1->posSuffixPatternForCurrency ==
- affix_2->posSuffixPatternForCurrency &&
- affix_1->patternType == affix_2->patternType;
-}
-
-U_CDECL_END
-
-
-// *****************************************************************************
-// class DecimalFormat
-// *****************************************************************************
-
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormat)
-// Constants for characters used in programmatic (unlocalized) patterns.
-#define kPatternZeroDigit ((UChar)0x0030) /*'0'*/
-#define kPatternSignificantDigit ((UChar)0x0040) /*'@'*/
-#define kPatternGroupingSeparator ((UChar)0x002C) /*','*/
-#define kPatternDecimalSeparator ((UChar)0x002E) /*'.'*/
-#define kPatternPerMill ((UChar)0x2030)
-#define kPatternPercent ((UChar)0x0025) /*'%'*/
-#define kPatternDigit ((UChar)0x0023) /*'#'*/
-#define kPatternSeparator ((UChar)0x003B) /*';'*/
-#define kPatternExponent ((UChar)0x0045) /*'E'*/
-#define kPatternPlus ((UChar)0x002B) /*'+'*/
-#define kPatternMinus ((UChar)0x002D) /*'-'*/
-#define kPatternPadEscape ((UChar)0x002A) /*'*'*/
-#define kQuote ((UChar)0x0027) /*'\''*/
-/**
- * The CURRENCY_SIGN is the standard Unicode symbol for currency. It
- * is used in patterns and substitued with either the currency symbol,
- * or if it is doubled, with the international currency symbol. If the
- * CURRENCY_SIGN is seen in a pattern, then the decimal separator is
- * replaced with the monetary decimal separator.
- */
-#define kCurrencySign ((UChar)0x00A4)
-#define kDefaultPad ((UChar)0x0020) /* */
-
-const int32_t DecimalFormat::kDoubleIntegerDigits = 309;
-const int32_t DecimalFormat::kDoubleFractionDigits = 340;
-
-const int32_t DecimalFormat::kMaxScientificIntegerDigits = 8;
-
-/**
- * These are the tags we expect to see in normal resource bundle files associated
- * with a locale.
- */
-const char DecimalFormat::fgNumberPatterns[]="NumberPatterns"; // Deprecated - not used
-static const char fgNumberElements[]="NumberElements";
-static const char fgLatn[]="latn";
-static const char fgPatterns[]="patterns";
-static const char fgDecimalFormat[]="decimalFormat";
-static const char fgCurrencyFormat[]="currencyFormat";
-
-inline int32_t _min(int32_t a, int32_t b) { return (a adoptedSymbols(symbolsToAdopt);
- if (U_FAILURE(status))
- return;
-
- if (adoptedSymbols.isNull())
- {
- adoptedSymbols.adoptInstead(
- new DecimalFormatSymbols(Locale::getDefault(), status));
- if (adoptedSymbols.isNull() && U_SUCCESS(status)) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
- if (U_FAILURE(status)) {
- return;
- }
- }
- fStaticSets = DecimalFormatStaticSets::getStaticSets(status);
- if (U_FAILURE(status)) {
- return;
- }
-
- UnicodeString str;
- // Uses the default locale's number format pattern if there isn't
- // one specified.
- if (pattern == NULL)
- {
- UErrorCode nsStatus = U_ZERO_ERROR;
- LocalPointer ns(
- NumberingSystem::createInstance(nsStatus));
- if (U_FAILURE(nsStatus)) {
- status = nsStatus;
- return;
- }
-
- int32_t len = 0;
- UResourceBundle *top = ures_open(NULL, Locale::getDefault().getName(), &status);
-
- UResourceBundle *resource = ures_getByKeyWithFallback(top, fgNumberElements, NULL, &status);
- resource = ures_getByKeyWithFallback(resource, ns->getName(), resource, &status);
- resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &status);
- const UChar *resStr = ures_getStringByKeyWithFallback(resource, fgDecimalFormat, &len, &status);
- if ( status == U_MISSING_RESOURCE_ERROR && uprv_strcmp(fgLatn,ns->getName())) {
- status = U_ZERO_ERROR;
- resource = ures_getByKeyWithFallback(top, fgNumberElements, resource, &status);
- resource = ures_getByKeyWithFallback(resource, fgLatn, resource, &status);
- resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &status);
- resStr = ures_getStringByKeyWithFallback(resource, fgDecimalFormat, &len, &status);
- }
- str.setTo(TRUE, resStr, len);
- pattern = &str;
- ures_close(resource);
- ures_close(top);
- }
-
- fImpl = new DecimalFormatImpl(this, *pattern, adoptedSymbols.getAlias(), parseErr, status);
- if (fImpl) {
- adoptedSymbols.orphan();
- } else if (U_SUCCESS(status)) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
- if (U_FAILURE(status)) {
- return;
- }
-
- if (U_FAILURE(status))
- {
- return;
- }
-
- const UnicodeString* patternUsed;
- UnicodeString currencyPluralPatternForOther;
- // apply pattern
- if (fStyle == UNUM_CURRENCY_PLURAL) {
- fCurrencyPluralInfo = new CurrencyPluralInfo(fImpl->fSymbols->getLocale(), status);
- if (U_FAILURE(status)) {
- return;
- }
-
- // the pattern used in format is not fixed until formatting,
- // in which, the number is known and
- // will be used to pick the right pattern based on plural count.
- // Here, set the pattern as the pattern of plural count == "other".
- // For most locale, the patterns are probably the same for all
- // plural count. If not, the right pattern need to be re-applied
- // during format.
- fCurrencyPluralInfo->getCurrencyPluralPattern(UNICODE_STRING("other", 5), currencyPluralPatternForOther);
- // TODO(refactor): Revisit, we are setting the pattern twice.
- fImpl->applyPatternFavorCurrencyPrecision(
- currencyPluralPatternForOther, status);
- patternUsed = ¤cyPluralPatternForOther;
+DecimalFormat::DecimalFormat(UErrorCode& status)
+ : DecimalFormat(nullptr, status) {
+ // Use the default locale and decimal pattern.
+ const char* localeName = Locale::getDefault().getName();
+ LocalPointer ns(NumberingSystem::createInstance(status));
+ UnicodeString patternString = utils::getPatternForStyle(
+ localeName,
+ ns->getName(),
+ CLDR_PATTERN_STYLE_DECIMAL,
+ status);
+ setPropertiesFromPattern(patternString, IGNORE_ROUNDING_IF_CURRENCY, status);
+ touch(status);
+}
+
+DecimalFormat::DecimalFormat(const UnicodeString& pattern, UErrorCode& status)
+ : DecimalFormat(nullptr, status) {
+ setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
+ touch(status);
+}
+
+DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt,
+ UErrorCode& status)
+ : DecimalFormat(symbolsToAdopt, status) {
+ setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
+ touch(status);
+}
+
+DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt,
+ UNumberFormatStyle style, UErrorCode& status)
+ : DecimalFormat(symbolsToAdopt, status) {
+ // If choice is a currency type, ignore the rounding information.
+ if (style == UNumberFormatStyle::UNUM_CURRENCY || style == UNumberFormatStyle::UNUM_CURRENCY_ISO ||
+ style == UNumberFormatStyle::UNUM_CURRENCY_ACCOUNTING ||
+ style == UNumberFormatStyle::UNUM_CASH_CURRENCY ||
+ style == UNumberFormatStyle::UNUM_CURRENCY_STANDARD ||
+ style == UNumberFormatStyle::UNUM_CURRENCY_PLURAL) {
+ setPropertiesFromPattern(pattern, IGNORE_ROUNDING_ALWAYS, status);
} else {
- patternUsed = pattern;
+ setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
}
-
- if (patternUsed->indexOf(kCurrencySign) != -1) {
- // initialize for currency, not only for plural format,
- // but also for mix parsing
- handleCurrencySignInPattern(status);
+ // Note: in Java, CurrencyPluralInfo is set in NumberFormat.java, but in C++, it is not set there,
+ // so we have to set it here.
+ if (style == UNumberFormatStyle::UNUM_CURRENCY_PLURAL) {
+ LocalPointer cpi(
+ new CurrencyPluralInfo(fields->symbols->getLocale(), status),
+ status);
+ if (U_FAILURE(status)) { return; }
+ fields->properties->currencyPluralInfo.fPtr.adoptInstead(cpi.orphan());
}
+ touch(status);
}
-void
-DecimalFormat::handleCurrencySignInPattern(UErrorCode& status) {
- // initialize for currency, not only for plural format,
- // but also for mix parsing
+DecimalFormat::DecimalFormat(const DecimalFormatSymbols* symbolsToAdopt, UErrorCode& status) {
+ LocalPointer adoptedSymbols(symbolsToAdopt);
+ fields = new DecimalFormatFields();
if (U_FAILURE(status)) {
return;
}
- if (fCurrencyPluralInfo == NULL) {
- fCurrencyPluralInfo = new CurrencyPluralInfo(fImpl->fSymbols->getLocale(), status);
- if (U_FAILURE(status)) {
- return;
- }
- }
- // need it for mix parsing
- if (fAffixPatternsForCurrency == NULL) {
- setupCurrencyAffixPatterns(status);
- }
-}
-
-static void
-applyPatternWithNoSideEffects(
- const UnicodeString& pattern,
- UParseError& parseError,
- UnicodeString &negPrefix,
- UnicodeString &negSuffix,
- UnicodeString &posPrefix,
- UnicodeString &posSuffix,
- UErrorCode& status) {
- if (U_FAILURE(status))
- {
+ if (fields == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
return;
}
- DecimalFormatPatternParser patternParser;
- DecimalFormatPattern out;
- patternParser.applyPatternWithoutExpandAffix(
- pattern,
- out,
- parseError,
- status);
- if (U_FAILURE(status)) {
- return;
+ fields->properties.adoptInsteadAndCheckErrorCode(new DecimalFormatProperties(), status);
+ fields->exportedProperties.adoptInsteadAndCheckErrorCode(new DecimalFormatProperties(), status);
+ if (adoptedSymbols.isNull()) {
+ fields->symbols.adoptInsteadAndCheckErrorCode(new DecimalFormatSymbols(status), status);
+ } else {
+ fields->symbols.adoptInsteadAndCheckErrorCode(adoptedSymbols.orphan(), status);
}
- negPrefix = out.fNegPrefixPattern;
- negSuffix = out.fNegSuffixPattern;
- posPrefix = out.fPosPrefixPattern;
- posSuffix = out.fPosSuffixPattern;
}
-void
-DecimalFormat::setupCurrencyAffixPatterns(UErrorCode& status) {
- if (U_FAILURE(status)) {
- return;
- }
- UParseError parseErr;
- fAffixPatternsForCurrency = initHashForAffixPattern(status);
- if (U_FAILURE(status)) {
- return;
- }
-
- NumberingSystem *ns = NumberingSystem::createInstance(fImpl->fSymbols->getLocale(),status);
- if (U_FAILURE(status)) {
- return;
- }
+#if UCONFIG_HAVE_PARSEALLINPUT
- // Save the default currency patterns of this locale.
- // Here, chose onlyApplyPatternWithoutExpandAffix without
- // expanding the affix patterns into affixes.
- UnicodeString currencyPattern;
- UErrorCode error = U_ZERO_ERROR;
-
- UResourceBundle *resource = ures_open(NULL, fImpl->fSymbols->getLocale().getName(), &error);
- UResourceBundle *numElements = ures_getByKeyWithFallback(resource, fgNumberElements, NULL, &error);
- resource = ures_getByKeyWithFallback(numElements, ns->getName(), resource, &error);
- resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &error);
- int32_t patLen = 0;
- const UChar *patResStr = ures_getStringByKeyWithFallback(resource, fgCurrencyFormat, &patLen, &error);
- if ( error == U_MISSING_RESOURCE_ERROR && uprv_strcmp(ns->getName(),fgLatn)) {
- error = U_ZERO_ERROR;
- resource = ures_getByKeyWithFallback(numElements, fgLatn, resource, &error);
- resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &error);
- patResStr = ures_getStringByKeyWithFallback(resource, fgCurrencyFormat, &patLen, &error);
- }
- ures_close(numElements);
- ures_close(resource);
- delete ns;
-
- if (U_SUCCESS(error)) {
- UnicodeString negPrefix;
- UnicodeString negSuffix;
- UnicodeString posPrefix;
- UnicodeString posSuffix;
- applyPatternWithNoSideEffects(UnicodeString(patResStr, patLen),
- parseErr,
- negPrefix, negSuffix, posPrefix, posSuffix, status);
- AffixPatternsForCurrency* affixPtn = new AffixPatternsForCurrency(
- negPrefix,
- negSuffix,
- posPrefix,
- posSuffix,
- UCURR_SYMBOL_NAME);
- fAffixPatternsForCurrency->put(UNICODE_STRING("default", 7), affixPtn, status);
- }
-
- // save the unique currency plural patterns of this locale.
- Hashtable* pluralPtn = fCurrencyPluralInfo->fPluralCountToCurrencyUnitPattern;
- const UHashElement* element = NULL;
- int32_t pos = UHASH_FIRST;
- Hashtable pluralPatternSet;
- while ((element = pluralPtn->nextElement(pos)) != NULL) {
- const UHashTok valueTok = element->value;
- const UnicodeString* value = (UnicodeString*)valueTok.pointer;
- const UHashTok keyTok = element->key;
- const UnicodeString* key = (UnicodeString*)keyTok.pointer;
- if (pluralPatternSet.geti(*value) != 1) {
- UnicodeString negPrefix;
- UnicodeString negSuffix;
- UnicodeString posPrefix;
- UnicodeString posSuffix;
- pluralPatternSet.puti(*value, 1, status);
- applyPatternWithNoSideEffects(
- *value, parseErr,
- negPrefix, negSuffix, posPrefix, posSuffix, status);
- AffixPatternsForCurrency* affixPtn = new AffixPatternsForCurrency(
- negPrefix,
- negSuffix,
- posPrefix,
- posSuffix,
- UCURR_LONG_NAME);
- fAffixPatternsForCurrency->put(*key, affixPtn, status);
- }
- }
+void DecimalFormat::setParseAllInput(UNumberFormatAttributeValue value) {
+ if (value == fields->properties->parseAllInput) { return; }
+ fields->properties->parseAllInput = value;
}
+#endif
-//------------------------------------------------------------------------------
+DecimalFormat&
+DecimalFormat::setAttribute(UNumberFormatAttribute attr, int32_t newValue, UErrorCode& status) {
+ if (U_FAILURE(status)) { return *this; }
-DecimalFormat::~DecimalFormat()
-{
- deleteHashForAffixPattern();
- delete fCurrencyPluralInfo;
- delete fImpl;
-}
+ switch (attr) {
+ case UNUM_LENIENT_PARSE:
+ setLenient(newValue != 0);
+ break;
-//------------------------------------------------------------------------------
-// copy constructor
+ case UNUM_PARSE_INT_ONLY:
+ setParseIntegerOnly(newValue != 0);
+ break;
-DecimalFormat::DecimalFormat(const DecimalFormat &source) :
- NumberFormat(source) {
- init();
- *this = source;
-}
+ case UNUM_GROUPING_USED:
+ setGroupingUsed(newValue != 0);
+ break;
-//------------------------------------------------------------------------------
-// assignment operator
+ case UNUM_DECIMAL_ALWAYS_SHOWN:
+ setDecimalSeparatorAlwaysShown(newValue != 0);
+ break;
-template
-static void _clone_ptr(T** pdest, const T* source) {
- delete *pdest;
- if (source == NULL) {
- *pdest = NULL;
- } else {
- *pdest = static_cast(source->clone());
- }
-}
+ case UNUM_MAX_INTEGER_DIGITS:
+ setMaximumIntegerDigits(newValue);
+ break;
-DecimalFormat&
-DecimalFormat::operator=(const DecimalFormat& rhs)
-{
- if(this != &rhs) {
- UErrorCode status = U_ZERO_ERROR;
- NumberFormat::operator=(rhs);
- if (fImpl == NULL) {
- fImpl = new DecimalFormatImpl(this, *rhs.fImpl, status);
- } else {
- fImpl->assign(*rhs.fImpl, status);
- }
- fStaticSets = DecimalFormatStaticSets::getStaticSets(status);
- fStyle = rhs.fStyle;
- _clone_ptr(&fCurrencyPluralInfo, rhs.fCurrencyPluralInfo);
- deleteHashForAffixPattern();
- if (rhs.fAffixPatternsForCurrency) {
- UErrorCode status = U_ZERO_ERROR;
- fAffixPatternsForCurrency = initHashForAffixPattern(status);
- copyHashForAffixPattern(rhs.fAffixPatternsForCurrency,
- fAffixPatternsForCurrency, status);
- }
- }
+ case UNUM_MIN_INTEGER_DIGITS:
+ setMinimumIntegerDigits(newValue);
+ break;
- return *this;
-}
+ case UNUM_INTEGER_DIGITS:
+ setMinimumIntegerDigits(newValue);
+ setMaximumIntegerDigits(newValue);
+ break;
-//------------------------------------------------------------------------------
+ case UNUM_MAX_FRACTION_DIGITS:
+ setMaximumFractionDigits(newValue);
+ break;
-UBool
-DecimalFormat::operator==(const Format& that) const
-{
- if (this == &that)
- return TRUE;
+ case UNUM_MIN_FRACTION_DIGITS:
+ setMinimumFractionDigits(newValue);
+ break;
- // NumberFormat::operator== guarantees this cast is safe
- const DecimalFormat* other = (DecimalFormat*)&that;
+ case UNUM_FRACTION_DIGITS:
+ setMinimumFractionDigits(newValue);
+ setMaximumFractionDigits(newValue);
+ break;
- return (
- NumberFormat::operator==(that) &&
- fBoolFlags.getAll() == other->fBoolFlags.getAll() &&
- *fImpl == *other->fImpl);
+ case UNUM_SIGNIFICANT_DIGITS_USED:
+ setSignificantDigitsUsed(newValue != 0);
+ break;
-}
+ case UNUM_MAX_SIGNIFICANT_DIGITS:
+ setMaximumSignificantDigits(newValue);
+ break;
-//------------------------------------------------------------------------------
+ case UNUM_MIN_SIGNIFICANT_DIGITS:
+ setMinimumSignificantDigits(newValue);
+ break;
-Format*
-DecimalFormat::clone() const
-{
- return new DecimalFormat(*this);
-}
+ case UNUM_MULTIPLIER:
+ setMultiplier(newValue);
+ break;
+ case UNUM_SCALE:
+ setMultiplierScale(newValue);
+ break;
-FixedDecimal
-DecimalFormat::getFixedDecimal(double number, UErrorCode &status) const {
- VisibleDigitsWithExponent digits;
- initVisibleDigitsWithExponent(number, digits, status);
- if (U_FAILURE(status)) {
- return FixedDecimal();
- }
- return FixedDecimal(digits.getMantissa());
-}
+ case UNUM_GROUPING_SIZE:
+ setGroupingSize(newValue);
+ break;
-VisibleDigitsWithExponent &
-DecimalFormat::initVisibleDigitsWithExponent(
- double number,
- VisibleDigitsWithExponent &digits,
- UErrorCode &status) const {
- return fImpl->initVisibleDigitsWithExponent(number, digits, status);
-}
+ case UNUM_ROUNDING_MODE:
+ setRoundingMode((DecimalFormat::ERoundingMode) newValue);
+ break;
-FixedDecimal
-DecimalFormat::getFixedDecimal(const Formattable &number, UErrorCode &status) const {
- VisibleDigitsWithExponent digits;
- initVisibleDigitsWithExponent(number, digits, status);
- if (U_FAILURE(status)) {
- return FixedDecimal();
- }
- return FixedDecimal(digits.getMantissa());
-}
+ case UNUM_FORMAT_WIDTH:
+ setFormatWidth(newValue);
+ break;
-VisibleDigitsWithExponent &
-DecimalFormat::initVisibleDigitsWithExponent(
- const Formattable &number,
- VisibleDigitsWithExponent &digits,
- UErrorCode &status) const {
- if (U_FAILURE(status)) {
- return digits;
- }
- if (!number.isNumeric()) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return digits;
- }
+ case UNUM_PADDING_POSITION:
+ /** The position at which padding will take place. */
+ setPadPosition((DecimalFormat::EPadPosition) newValue);
+ break;
- DigitList *dl = number.getDigitList();
- if (dl != NULL) {
- DigitList dlCopy(*dl);
- return fImpl->initVisibleDigitsWithExponent(
- dlCopy, digits, status);
- }
+ case UNUM_SECONDARY_GROUPING_SIZE:
+ setSecondaryGroupingSize(newValue);
+ break;
- Formattable::Type type = number.getType();
- if (type == Formattable::kDouble || type == Formattable::kLong) {
- return fImpl->initVisibleDigitsWithExponent(
- number.getDouble(status), digits, status);
- }
- return fImpl->initVisibleDigitsWithExponent(
- number.getInt64(), digits, status);
-}
+#if UCONFIG_HAVE_PARSEALLINPUT
+ case UNUM_PARSE_ALL_INPUT:
+ setParseAllInput((UNumberFormatAttributeValue) newValue);
+ break;
+#endif
+ case UNUM_PARSE_NO_EXPONENT:
+ setParseNoExponent((UBool) newValue);
+ break;
-// Create a fixed decimal from a DigitList.
-// The digit list may be modified.
-// Internal function only.
-FixedDecimal
-DecimalFormat::getFixedDecimal(DigitList &number, UErrorCode &status) const {
- VisibleDigitsWithExponent digits;
- initVisibleDigitsWithExponent(number, digits, status);
- if (U_FAILURE(status)) {
- return FixedDecimal();
- }
- return FixedDecimal(digits.getMantissa());
-}
+ case UNUM_PARSE_DECIMAL_MARK_REQUIRED:
+ setDecimalPatternMatchRequired((UBool) newValue);
+ break;
-VisibleDigitsWithExponent &
-DecimalFormat::initVisibleDigitsWithExponent(
- DigitList &number,
- VisibleDigitsWithExponent &digits,
- UErrorCode &status) const {
- return fImpl->initVisibleDigitsWithExponent(
- number, digits, status);
-}
+ case UNUM_CURRENCY_USAGE:
+ setCurrencyUsage((UCurrencyUsage) newValue, &status);
+ break;
+ case UNUM_MINIMUM_GROUPING_DIGITS:
+ setMinimumGroupingDigits(newValue);
+ break;
-//------------------------------------------------------------------------------
+ case UNUM_PARSE_CASE_SENSITIVE:
+ setParseCaseSensitive(static_cast(newValue));
+ break;
-UnicodeString&
-DecimalFormat::format(int32_t number,
- UnicodeString& appendTo,
- FieldPosition& fieldPosition) const
-{
- UErrorCode status = U_ZERO_ERROR;
- return fImpl->format(number, appendTo, fieldPosition, status);
-}
+ case UNUM_SIGN_ALWAYS_SHOWN:
+ setSignAlwaysShown(static_cast(newValue));
+ break;
-UnicodeString&
-DecimalFormat::format(int32_t number,
- UnicodeString& appendTo,
- FieldPosition& fieldPosition,
- UErrorCode& status) const
-{
- return fImpl->format(number, appendTo, fieldPosition, status);
-}
+ case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
+ setFormatFailIfMoreThanMaxDigits(static_cast(newValue));
+ break;
-UnicodeString&
-DecimalFormat::format(int32_t number,
- UnicodeString& appendTo,
- FieldPositionIterator* posIter,
- UErrorCode& status) const
-{
- return fImpl->format(number, appendTo, posIter, status);
+ default:
+ status = U_UNSUPPORTED_ERROR;
+ break;
+ }
+ return *this;
}
+int32_t DecimalFormat::getAttribute(UNumberFormatAttribute attr, UErrorCode& status) const {
+ if (U_FAILURE(status)) { return -1; }
+ switch (attr) {
+ case UNUM_LENIENT_PARSE:
+ return isLenient();
-//------------------------------------------------------------------------------
+ case UNUM_PARSE_INT_ONLY:
+ return isParseIntegerOnly();
-UnicodeString&
-DecimalFormat::format(int64_t number,
- UnicodeString& appendTo,
- FieldPosition& fieldPosition) const
-{
- UErrorCode status = U_ZERO_ERROR; /* ignored */
- return fImpl->format(number, appendTo, fieldPosition, status);
-}
+ case UNUM_GROUPING_USED:
+ return isGroupingUsed();
-UnicodeString&
-DecimalFormat::format(int64_t number,
- UnicodeString& appendTo,
- FieldPosition& fieldPosition,
- UErrorCode& status) const
-{
- return fImpl->format(number, appendTo, fieldPosition, status);
-}
+ case UNUM_DECIMAL_ALWAYS_SHOWN:
+ return isDecimalSeparatorAlwaysShown();
-UnicodeString&
-DecimalFormat::format(int64_t number,
- UnicodeString& appendTo,
- FieldPositionIterator* posIter,
- UErrorCode& status) const
-{
- return fImpl->format(number, appendTo, posIter, status);
-}
+ case UNUM_MAX_INTEGER_DIGITS:
+ return getMaximumIntegerDigits();
-//------------------------------------------------------------------------------
+ case UNUM_MIN_INTEGER_DIGITS:
+ return getMinimumIntegerDigits();
-UnicodeString&
-DecimalFormat::format( double number,
- UnicodeString& appendTo,
- FieldPosition& fieldPosition) const
-{
- UErrorCode status = U_ZERO_ERROR; /* ignored */
- return fImpl->format(number, appendTo, fieldPosition, status);
-}
+ case UNUM_INTEGER_DIGITS:
+ // TBD: what should this return?
+ return getMinimumIntegerDigits();
-UnicodeString&
-DecimalFormat::format( double number,
- UnicodeString& appendTo,
- FieldPosition& fieldPosition,
- UErrorCode& status) const
-{
- return fImpl->format(number, appendTo, fieldPosition, status);
-}
+ case UNUM_MAX_FRACTION_DIGITS:
+ return getMaximumFractionDigits();
-UnicodeString&
-DecimalFormat::format( double number,
- UnicodeString& appendTo,
- FieldPositionIterator* posIter,
- UErrorCode& status) const
-{
- return fImpl->format(number, appendTo, posIter, status);
-}
+ case UNUM_MIN_FRACTION_DIGITS:
+ return getMinimumFractionDigits();
-//------------------------------------------------------------------------------
+ case UNUM_FRACTION_DIGITS:
+ // TBD: what should this return?
+ return getMinimumFractionDigits();
+ case UNUM_SIGNIFICANT_DIGITS_USED:
+ return areSignificantDigitsUsed();
-UnicodeString&
-DecimalFormat::format(StringPiece number,
- UnicodeString &toAppendTo,
- FieldPositionIterator *posIter,
- UErrorCode &status) const
-{
- return fImpl->format(number, toAppendTo, posIter, status);
-}
+ case UNUM_MAX_SIGNIFICANT_DIGITS:
+ return getMaximumSignificantDigits();
+ case UNUM_MIN_SIGNIFICANT_DIGITS:
+ return getMinimumSignificantDigits();
-UnicodeString&
-DecimalFormat::format(const DigitList &number,
- UnicodeString &appendTo,
- FieldPositionIterator *posIter,
- UErrorCode &status) const {
- return fImpl->format(number, appendTo, posIter, status);
-}
+ case UNUM_MULTIPLIER:
+ return getMultiplier();
+ case UNUM_SCALE:
+ return getMultiplierScale();
-UnicodeString&
-DecimalFormat::format(const DigitList &number,
- UnicodeString& appendTo,
- FieldPosition& pos,
- UErrorCode &status) const {
- return fImpl->format(number, appendTo, pos, status);
-}
+ case UNUM_GROUPING_SIZE:
+ return getGroupingSize();
-UnicodeString&
-DecimalFormat::format(const VisibleDigitsWithExponent &number,
- UnicodeString &appendTo,
- FieldPositionIterator *posIter,
- UErrorCode &status) const {
- return fImpl->format(number, appendTo, posIter, status);
-}
+ case UNUM_ROUNDING_MODE:
+ return getRoundingMode();
+ case UNUM_FORMAT_WIDTH:
+ return getFormatWidth();
-UnicodeString&
-DecimalFormat::format(const VisibleDigitsWithExponent &number,
- UnicodeString& appendTo,
- FieldPosition& pos,
- UErrorCode &status) const {
- return fImpl->format(number, appendTo, pos, status);
-}
+ case UNUM_PADDING_POSITION:
+ return getPadPosition();
-DigitList&
-DecimalFormat::_round(const DigitList& number, DigitList& adjustedNum, UBool& isNegative, UErrorCode& status) const {
- adjustedNum = number;
- fImpl->round(adjustedNum, status);
- isNegative = !adjustedNum.isPositive();
- return adjustedNum;
-}
+ case UNUM_SECONDARY_GROUPING_SIZE:
+ return getSecondaryGroupingSize();
-void
-DecimalFormat::parse(const UnicodeString& text,
- Formattable& result,
- ParsePosition& parsePosition) const {
- parse(text, result, parsePosition, NULL);
-}
-
-CurrencyAmount* DecimalFormat::parseCurrency(const UnicodeString& text,
- ParsePosition& pos) const {
- Formattable parseResult;
- int32_t start = pos.getIndex();
- UChar curbuf[4] = {};
- parse(text, parseResult, pos, curbuf);
- if (pos.getIndex() != start) {
- UErrorCode ec = U_ZERO_ERROR;
- LocalPointer currAmt(new CurrencyAmount(parseResult, curbuf, ec), ec);
- if (U_FAILURE(ec)) {
- pos.setIndex(start); // indicate failure
- } else {
- return currAmt.orphan();
- }
- }
- return NULL;
-}
-
-/**
- * Parses the given text as a number, optionally providing a currency amount.
- * @param text the string to parse
- * @param result output parameter for the numeric result.
- * @param parsePosition input-output position; on input, the
- * position within text to match; must have 0 <= pos.getIndex() <
- * text.length(); on output, the position after the last matched
- * character. If the parse fails, the position in unchanged upon
- * output.
- * @param currency if non-NULL, it should point to a 4-UChar buffer.
- * In this case the text is parsed as a currency format, and the
- * ISO 4217 code for the parsed currency is put into the buffer.
- * Otherwise the text is parsed as a non-currency format.
- */
-void DecimalFormat::parse(const UnicodeString& text,
- Formattable& result,
- ParsePosition& parsePosition,
- UChar* currency) const {
- int32_t startIdx, backup;
- int32_t i = startIdx = backup = parsePosition.getIndex();
-
- // clear any old contents in the result. In particular, clears any DigitList
- // that it may be holding.
- result.setLong(0);
- if (currency != NULL) {
- for (int32_t ci=0; ci<4; ci++) {
- currency[ci] = 0;
- }
- }
+ case UNUM_PARSE_NO_EXPONENT:
+ return isParseNoExponent();
- // Handle NaN as a special case:
- int32_t formatWidth = fImpl->getOldFormatWidth();
+ case UNUM_PARSE_DECIMAL_MARK_REQUIRED:
+ return isDecimalPatternMatchRequired();
- // Skip padding characters, if around prefix
- if (formatWidth > 0 && (
- fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforePrefix ||
- fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterPrefix)) {
- i = skipPadding(text, i);
- }
+ case UNUM_CURRENCY_USAGE:
+ return getCurrencyUsage();
- if (isLenient()) {
- // skip any leading whitespace
- i = backup = skipUWhiteSpace(text, i);
- }
+ case UNUM_MINIMUM_GROUPING_DIGITS:
+ return getMinimumGroupingDigits();
- // If the text is composed of the representation of NaN, returns NaN.length
- const UnicodeString *nan = &fImpl->getConstSymbol(DecimalFormatSymbols::kNaNSymbol);
- int32_t nanLen = (text.compare(i, nan->length(), *nan)
- ? 0 : nan->length());
- if (nanLen) {
- i += nanLen;
- if (formatWidth > 0 && (fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforeSuffix || fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterSuffix)) {
- i = skipPadding(text, i);
- }
- parsePosition.setIndex(i);
- result.setDouble(uprv_getNaN());
- return;
- }
+ case UNUM_PARSE_CASE_SENSITIVE:
+ return isParseCaseSensitive();
- // NaN parse failed; start over
- i = backup;
- parsePosition.setIndex(i);
+ case UNUM_SIGN_ALWAYS_SHOWN:
+ return isSignAlwaysShown();
- // status is used to record whether a number is infinite.
- UBool status[fgStatusLength];
+ case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
+ return isFormatFailIfMoreThanMaxDigits();
- DigitList *digits = result.getInternalDigitList(); // get one from the stack buffer
- if (digits == NULL) {
- return; // no way to report error from here.
+ default:
+ status = U_UNSUPPORTED_ERROR;
+ break;
}
- if (fImpl->fMonetary) {
- if (!parseForCurrency(text, parsePosition, *digits,
- status, currency)) {
- return;
- }
- } else {
- if (!subparse(text,
- &fImpl->fAffixes.fNegativePrefix.getOtherVariant().toString(),
- &fImpl->fAffixes.fNegativeSuffix.getOtherVariant().toString(),
- &fImpl->fAffixes.fPositivePrefix.getOtherVariant().toString(),
- &fImpl->fAffixes.fPositiveSuffix.getOtherVariant().toString(),
- FALSE, UCURR_SYMBOL_NAME,
- parsePosition, *digits, status, currency)) {
- debug("!subparse(...) - rewind");
- parsePosition.setIndex(startIdx);
- return;
- }
- }
+ return -1; /* undefined */
+}
- // Handle infinity
- if (status[fgStatusInfinite]) {
- double inf = uprv_getInfinity();
- result.setDouble(digits->isPositive() ? inf : -inf);
- // TODO: set the dl to infinity, and let it fall into the code below.
- }
+void DecimalFormat::setGroupingUsed(UBool enabled) {
+ if (UBOOL_TO_BOOL(enabled) == fields->properties->groupingUsed) { return; }
+ NumberFormat::setGroupingUsed(enabled); // to set field for compatibility
+ fields->properties->groupingUsed = enabled;
+ touchNoError();
+}
- else {
+void DecimalFormat::setParseIntegerOnly(UBool value) {
+ if (UBOOL_TO_BOOL(value) == fields->properties->parseIntegerOnly) { return; }
+ NumberFormat::setParseIntegerOnly(value); // to set field for compatibility
+ fields->properties->parseIntegerOnly = value;
+ touchNoError();
+}
- if (!fImpl->fMultiplier.isZero()) {
- UErrorCode ec = U_ZERO_ERROR;
- digits->div(fImpl->fMultiplier, ec);
- }
+void DecimalFormat::setLenient(UBool enable) {
+ ParseMode mode = enable ? PARSE_MODE_LENIENT : PARSE_MODE_STRICT;
+ if (!fields->properties->parseMode.isNull() && mode == fields->properties->parseMode.getNoError()) { return; }
+ NumberFormat::setLenient(enable); // to set field for compatibility
+ fields->properties->parseMode = mode;
+ touchNoError();
+}
- if (fImpl->fScale != 0) {
- DigitList ten;
- ten.set((int32_t)10);
- if (fImpl->fScale > 0) {
- for (int32_t i = fImpl->fScale; i > 0; i--) {
- UErrorCode ec = U_ZERO_ERROR;
- digits->div(ten,ec);
- }
- } else {
- for (int32_t i = fImpl->fScale; i < 0; i++) {
- UErrorCode ec = U_ZERO_ERROR;
- digits->mult(ten,ec);
- }
- }
- }
+DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt,
+ UParseError&, UErrorCode& status)
+ : DecimalFormat(symbolsToAdopt, status) {
+ // TODO: What is parseError for?
+ setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
+ touch(status);
+}
- // Negative zero special case:
- // if parsing integerOnly, change to +0, which goes into an int32 in a Formattable.
- // if not parsing integerOnly, leave as -0, which a double can represent.
- if (digits->isZero() && !digits->isPositive() && isParseIntegerOnly()) {
- digits->setPositive(TRUE);
- }
- result.adoptDigitList(digits);
- }
-}
-
-
-
-UBool
-DecimalFormat::parseForCurrency(const UnicodeString& text,
- ParsePosition& parsePosition,
- DigitList& digits,
- UBool* status,
- UChar* currency) const {
- UnicodeString positivePrefix;
- UnicodeString positiveSuffix;
- UnicodeString negativePrefix;
- UnicodeString negativeSuffix;
- fImpl->fPositivePrefixPattern.toString(positivePrefix);
- fImpl->fPositiveSuffixPattern.toString(positiveSuffix);
- fImpl->fNegativePrefixPattern.toString(negativePrefix);
- fImpl->fNegativeSuffixPattern.toString(negativeSuffix);
-
- int origPos = parsePosition.getIndex();
- int maxPosIndex = origPos;
- int maxErrorPos = -1;
- // First, parse against current pattern.
- // Since current pattern could be set by applyPattern(),
- // it could be an arbitrary pattern, and it may not be the one
- // defined in current locale.
- UBool tmpStatus[fgStatusLength];
- ParsePosition tmpPos(origPos);
- DigitList tmpDigitList;
- UBool found;
- if (fStyle == UNUM_CURRENCY_PLURAL) {
- found = subparse(text,
- &negativePrefix, &negativeSuffix,
- &positivePrefix, &positiveSuffix,
- TRUE, UCURR_LONG_NAME,
- tmpPos, tmpDigitList, tmpStatus, currency);
- } else {
- found = subparse(text,
- &negativePrefix, &negativeSuffix,
- &positivePrefix, &positiveSuffix,
- TRUE, UCURR_SYMBOL_NAME,
- tmpPos, tmpDigitList, tmpStatus, currency);
- }
- if (found) {
- if (tmpPos.getIndex() > maxPosIndex) {
- maxPosIndex = tmpPos.getIndex();
- for (int32_t i = 0; i < fgStatusLength; ++i) {
- status[i] = tmpStatus[i];
- }
- digits = tmpDigitList;
- }
- } else {
- maxErrorPos = tmpPos.getErrorIndex();
- }
- // Then, parse against affix patterns.
- // Those are currency patterns and currency plural patterns.
- int32_t pos = UHASH_FIRST;
- const UHashElement* element = NULL;
- while ( (element = fAffixPatternsForCurrency->nextElement(pos)) != NULL ) {
- const UHashTok valueTok = element->value;
- const AffixPatternsForCurrency* affixPtn = (AffixPatternsForCurrency*)valueTok.pointer;
- UBool tmpStatus[fgStatusLength];
- ParsePosition tmpPos(origPos);
- DigitList tmpDigitList;
-
-#ifdef FMT_DEBUG
- debug("trying affix for currency..");
- affixPtn->dump();
-#endif
+DecimalFormat::DecimalFormat(const UnicodeString& pattern, const DecimalFormatSymbols& symbols,
+ UErrorCode& status)
+ : DecimalFormat(new DecimalFormatSymbols(symbols), status) {
+ setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
+ touch(status);
+}
- UBool result = subparse(text,
- &affixPtn->negPrefixPatternForCurrency,
- &affixPtn->negSuffixPatternForCurrency,
- &affixPtn->posPrefixPatternForCurrency,
- &affixPtn->posSuffixPatternForCurrency,
- TRUE, affixPtn->patternType,
- tmpPos, tmpDigitList, tmpStatus, currency);
- if (result) {
- found = true;
- if (tmpPos.getIndex() > maxPosIndex) {
- maxPosIndex = tmpPos.getIndex();
- for (int32_t i = 0; i < fgStatusLength; ++i) {
- status[i] = tmpStatus[i];
- }
- digits = tmpDigitList;
- }
- } else {
- maxErrorPos = (tmpPos.getErrorIndex() > maxErrorPos) ?
- tmpPos.getErrorIndex() : maxErrorPos;
- }
+DecimalFormat::DecimalFormat(const DecimalFormat& source) : NumberFormat(source) {
+ // Note: it is not safe to copy fields->formatter or fWarehouse directly because fields->formatter might have
+ // dangling pointers to fields inside fWarehouse. The safe thing is to re-construct fields->formatter from
+ // the property bag, despite being somewhat slower.
+ fields = new DecimalFormatFields();
+ if (fields == nullptr) {
+ return;
}
- // Finally, parse against simple affix to find the match.
- // For example, in TestMonster suite,
- // if the to-be-parsed text is "-\u00A40,00".
- // complexAffixCompare will not find match,
- // since there is no ISO code matches "\u00A4",
- // and the parse stops at "\u00A4".
- // We will just use simple affix comparison (look for exact match)
- // to pass it.
- //
- // TODO: We should parse against simple affix first when
- // output currency is not requested. After the complex currency
- // parsing implementation was introduced, the default currency
- // instance parsing slowed down because of the new code flow.
- // I filed #10312 - Yoshito
- UBool tmpStatus_2[fgStatusLength];
- ParsePosition tmpPos_2(origPos);
- DigitList tmpDigitList_2;
-
- // Disable complex currency parsing and try it again.
- UBool result = subparse(text,
- &fImpl->fAffixes.fNegativePrefix.getOtherVariant().toString(),
- &fImpl->fAffixes.fNegativeSuffix.getOtherVariant().toString(),
- &fImpl->fAffixes.fPositivePrefix.getOtherVariant().toString(),
- &fImpl->fAffixes.fPositiveSuffix.getOtherVariant().toString(),
- FALSE /* disable complex currency parsing */, UCURR_SYMBOL_NAME,
- tmpPos_2, tmpDigitList_2, tmpStatus_2,
- currency);
- if (result) {
- if (tmpPos_2.getIndex() > maxPosIndex) {
- maxPosIndex = tmpPos_2.getIndex();
- for (int32_t i = 0; i < fgStatusLength; ++i) {
- status[i] = tmpStatus_2[i];
- }
- digits = tmpDigitList_2;
- }
- found = true;
- } else {
- maxErrorPos = (tmpPos_2.getErrorIndex() > maxErrorPos) ?
- tmpPos_2.getErrorIndex() : maxErrorPos;
+ fields->properties.adoptInstead(new DecimalFormatProperties(*source.fields->properties));
+ fields->symbols.adoptInstead(new DecimalFormatSymbols(*source.fields->symbols));
+ fields->exportedProperties.adoptInstead(new DecimalFormatProperties());
+ if (fields->properties == nullptr || fields->symbols == nullptr || fields->exportedProperties == nullptr) {
+ return;
}
+ touchNoError();
+}
- if (!found) {
- //parsePosition.setIndex(origPos);
- parsePosition.setErrorIndex(maxErrorPos);
- } else {
- parsePosition.setIndex(maxPosIndex);
- parsePosition.setErrorIndex(-1);
- }
- return found;
-}
-
-
-/**
- * Parse the given text into a number. The text is parsed beginning at
- * parsePosition, until an unparseable character is seen.
- * @param text the string to parse.
- * @param negPrefix negative prefix.
- * @param negSuffix negative suffix.
- * @param posPrefix positive prefix.
- * @param posSuffix positive suffix.
- * @param complexCurrencyParsing whether it is complex currency parsing or not.
- * @param type the currency type to parse against, LONG_NAME only or not.
- * @param parsePosition The position at which to being parsing. Upon
- * return, the first unparsed character.
- * @param digits the DigitList to set to the parsed value.
- * @param status output param containing boolean status flags indicating
- * whether the value was infinite and whether it was positive.
- * @param currency return value for parsed currency, for generic
- * currency parsing mode, or NULL for normal parsing. In generic
- * currency parsing mode, any currency is parsed, not just the
- * currency that this formatter is set to.
- */
-UBool DecimalFormat::subparse(const UnicodeString& text,
- const UnicodeString* negPrefix,
- const UnicodeString* negSuffix,
- const UnicodeString* posPrefix,
- const UnicodeString* posSuffix,
- UBool complexCurrencyParsing,
- int8_t type,
- ParsePosition& parsePosition,
- DigitList& digits, UBool* status,
- UChar* currency) const
-{
- // The parsing process builds up the number as char string, in the neutral format that
- // will be acceptable to the decNumber library, then at the end passes that string
- // off for conversion to a decNumber.
- UErrorCode err = U_ZERO_ERROR;
- CharString parsedNum;
- digits.setToZero();
-
- int32_t position = parsePosition.getIndex();
- int32_t oldStart = position;
- int32_t textLength = text.length(); // One less pointer to follow
- UBool strictParse = !isLenient();
- UChar32 zero = fImpl->getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
- const UnicodeString *groupingString = &fImpl->getConstSymbol(
- !fImpl->fMonetary ?
- DecimalFormatSymbols::kGroupingSeparatorSymbol : DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol);
- UChar32 groupingChar = groupingString->char32At(0);
- int32_t groupingStringLength = groupingString->length();
- int32_t groupingCharLength = U16_LENGTH(groupingChar);
- UBool groupingUsed = isGroupingUsed();
-#ifdef FMT_DEBUG
- UChar dbgbuf[300];
- UnicodeString s(dbgbuf,0,300);;
- s.append((UnicodeString)"PARSE \"").append(text.tempSubString(position)).append((UnicodeString)"\" " );
-#define DBGAPPD(x) if(x) { s.append(UnicodeString(#x "=")); if(x->isEmpty()) { s.append(UnicodeString("")); } else { s.append(*x); } s.append(UnicodeString(" ")); } else { s.append(UnicodeString(#x "=NULL ")); }
- DBGAPPD(negPrefix);
- DBGAPPD(negSuffix);
- DBGAPPD(posPrefix);
- DBGAPPD(posSuffix);
- debugout(s);
-#endif
-
- UBool fastParseOk = false; /* TRUE iff fast parse is OK */
- // UBool fastParseHadDecimal = FALSE; /* true if fast parse saw a decimal point. */
- if((fImpl->isParseFastpath()) && !fImpl->fMonetary &&
- text.length()>0 &&
- text.length()<32 &&
- (posPrefix==NULL||posPrefix->isEmpty()) &&
- (posSuffix==NULL||posSuffix->isEmpty()) &&
- // (negPrefix==NULL||negPrefix->isEmpty()) &&
- // (negSuffix==NULL||(negSuffix->isEmpty()) ) &&
- TRUE) { // optimized path
- int j=position;
- int l=text.length();
- int digitCount=0;
- UChar32 ch = text.char32At(j);
- const UnicodeString *decimalString = &fImpl->getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
- UChar32 decimalChar = 0;
- UBool intOnly = FALSE;
- UChar32 lookForGroup = (groupingUsed&&intOnly&&strictParse)?groupingChar:0;
-
- int32_t decimalCount = decimalString->countChar32(0,3);
- if(isParseIntegerOnly()) {
- decimalChar = 0; // not allowed
- intOnly = TRUE; // Don't look for decimals.
- } else if(decimalCount==1) {
- decimalChar = decimalString->char32At(0); // Look for this decimal
- } else if(decimalCount==0) {
- decimalChar=0; // NO decimal set
- } else {
- j=l+1;//Set counter to end of line, so that we break. Unknown decimal situation.
- }
-
-#ifdef FMT_DEBUG
- printf("Preparing to do fastpath parse: decimalChar=U+%04X, groupingChar=U+%04X, first ch=U+%04X intOnly=%c strictParse=%c\n",
- decimalChar, groupingChar, ch,
- (intOnly)?'y':'n',
- (strictParse)?'y':'n');
-#endif
- if(ch==0x002D) { // '-'
- j=l+1;//=break - negative number.
-
- /*
- parsedNum.append('-',err);
- j+=U16_LENGTH(ch);
- if(j=0 && digit <= 9) {
- parsedNum.append((char)(digit + '0'), err);
- if((digitCount>0) || digit!=0 || j==(l-1)) {
- digitCount++;
- }
- } else if(ch == 0) { // break out
- digitCount=-1;
- break;
- } else if(ch == decimalChar) {
- parsedNum.append((char)('.'), err);
- decimalChar=0; // no more decimals.
- // fastParseHadDecimal=TRUE;
- } else if(ch == lookForGroup) {
- // ignore grouping char. No decimals, so it has to be an ignorable grouping sep
- } else if(intOnly && (lookForGroup!=0) && !u_isdigit(ch)) {
- // parsing integer only and can fall through
- } else {
- digitCount=-1; // fail - fall through to slow parse
- break;
- }
- j+=U16_LENGTH(ch);
- ch = text.char32At(j); // for next
- }
- if(
- ((j==l)||intOnly) // end OR only parsing integer
- && (digitCount>0)) { // and have at least one digit
- fastParseOk=true; // Fast parse OK!
-
-#ifdef SKIP_OPT
- debug("SKIP_OPT");
- /* for testing, try it the slow way. also */
- fastParseOk=false;
- parsedNum.clear();
-#else
- parsePosition.setIndex(position=j);
- status[fgStatusInfinite]=false;
-#endif
- } else {
- // was not OK. reset, retry
-#ifdef FMT_DEBUG
- printf("Fall through: j=%d, l=%d, digitCount=%d\n", j, l, digitCount);
-#endif
- parsedNum.clear();
- }
- } else {
-#ifdef FMT_DEBUG
- printf("Could not fastpath parse. ");
- printf("text.length()=%d ", text.length());
- printf("posPrefix=%p posSuffix=%p ", posPrefix, posSuffix);
+DecimalFormat& DecimalFormat::operator=(const DecimalFormat& rhs) {
+ *fields->properties = *rhs.fields->properties;
+ fields->exportedProperties->clear();
+ fields->symbols.adoptInstead(new DecimalFormatSymbols(*rhs.fields->symbols));
+ touchNoError();
+ return *this;
+}
- printf("\n");
-#endif
- }
+DecimalFormat::~DecimalFormat() {
+ delete fields->atomicParser.exchange(nullptr);
+ delete fields->atomicCurrencyParser.exchange(nullptr);
+ delete fields;
+}
- UnicodeString formatPattern;
- toPattern(formatPattern);
+Format* DecimalFormat::clone() const {
+ return new DecimalFormat(*this);
+}
- if(!fastParseOk
-#if UCONFIG_HAVE_PARSEALLINPUT
- && fParseAllInput!=UNUM_YES
-#endif
- )
- {
- int32_t formatWidth = fImpl->getOldFormatWidth();
- // Match padding before prefix
- if (formatWidth > 0 && fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforePrefix) {
- position = skipPadding(text, position);
- }
-
- // Match positive and negative prefixes; prefer longest match.
- int32_t posMatch = compareAffix(text, position, FALSE, TRUE, posPrefix, complexCurrencyParsing, type, currency);
- int32_t negMatch = compareAffix(text, position, TRUE, TRUE, negPrefix, complexCurrencyParsing, type, currency);
- if (posMatch >= 0 && negMatch >= 0) {
- if (posMatch > negMatch) {
- negMatch = -1;
- } else if (negMatch > posMatch) {
- posMatch = -1;
- }
- }
- if (posMatch >= 0) {
- position += posMatch;
- parsedNum.append('+', err);
- } else if (negMatch >= 0) {
- position += negMatch;
- parsedNum.append('-', err);
- } else if (strictParse){
- parsePosition.setErrorIndex(position);
- return FALSE;
- } else {
- // Temporary set positive. This might be changed after checking suffix
- parsedNum.append('+', err);
+UBool DecimalFormat::operator==(const Format& other) const {
+ auto* otherDF = dynamic_cast(&other);
+ if (otherDF == nullptr) {
+ return false;
}
+ return *fields->properties == *otherDF->fields->properties && *fields->symbols == *otherDF->fields->symbols;
+}
- // Match padding before prefix
- if (formatWidth > 0 && fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterPrefix) {
- position = skipPadding(text, position);
+UnicodeString& DecimalFormat::format(double number, UnicodeString& appendTo, FieldPosition& pos) const {
+ if (pos.getField() == FieldPosition::DONT_CARE && fastFormatDouble(number, appendTo)) {
+ return appendTo;
}
+ UErrorCode localStatus = U_ZERO_ERROR;
+ FormattedNumber output = fields->formatter->formatDouble(number, localStatus);
+ fieldPositionHelper(output, pos, appendTo.length(), localStatus);
+ auto appendable = UnicodeStringAppendable(appendTo);
+ output.appendTo(appendable);
+ return appendTo;
+}
- if (! strictParse) {
- position = skipUWhiteSpace(text, position);
+UnicodeString& DecimalFormat::format(double number, UnicodeString& appendTo, FieldPosition& pos,
+ UErrorCode& status) const {
+ if (pos.getField() == FieldPosition::DONT_CARE && fastFormatDouble(number, appendTo)) {
+ return appendTo;
}
+ FormattedNumber output = fields->formatter->formatDouble(number, status);
+ fieldPositionHelper(output, pos, appendTo.length(), status);
+ auto appendable = UnicodeStringAppendable(appendTo);
+ output.appendTo(appendable);
+ return appendTo;
+}
- // process digits or Inf, find decimal position
- const UnicodeString *inf = &fImpl->getConstSymbol(DecimalFormatSymbols::kInfinitySymbol);
- int32_t infLen = (text.compare(position, inf->length(), *inf)
- ? 0 : inf->length());
- position += infLen; // infLen is non-zero when it does equal to infinity
- status[fgStatusInfinite] = infLen != 0;
-
- if (infLen != 0) {
- parsedNum.append("Infinity", err);
- } else {
- // We now have a string of digits, possibly with grouping symbols,
- // and decimal points. We want to process these into a DigitList.
- // We don't want to put a bunch of leading zeros into the DigitList
- // though, so we keep track of the location of the decimal point,
- // put only significant digits into the DigitList, and adjust the
- // exponent as needed.
-
-
- UBool strictFail = FALSE; // did we exit with a strict parse failure?
- int32_t lastGroup = -1; // after which digit index did we last see a grouping separator?
- int32_t currGroup = -1; // for temporary storage the digit index of the current grouping separator
- int32_t gs2 = fImpl->fEffGrouping.fGrouping2 == 0 ? fImpl->fEffGrouping.fGrouping : fImpl->fEffGrouping.fGrouping2;
-
- const UnicodeString *decimalString;
- if (fImpl->fMonetary) {
- decimalString = &fImpl->getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
- } else {
- decimalString = &fImpl->getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
- }
- UChar32 decimalChar = decimalString->char32At(0);
- int32_t decimalStringLength = decimalString->length();
- int32_t decimalCharLength = U16_LENGTH(decimalChar);
-
- UBool sawDecimal = FALSE;
- UChar32 sawDecimalChar = 0xFFFF;
- UBool sawGrouping = FALSE;
- UChar32 sawGroupingChar = 0xFFFF;
- UBool sawDigit = FALSE;
- int32_t backup = -1;
- int32_t digit;
-
- // equivalent grouping and decimal support
- const UnicodeSet *decimalSet = NULL;
- const UnicodeSet *groupingSet = NULL;
-
- if (decimalCharLength == decimalStringLength) {
- decimalSet = DecimalFormatStaticSets::getSimilarDecimals(decimalChar, strictParse);
- }
-
- if (groupingCharLength == groupingStringLength) {
- if (strictParse) {
- groupingSet = fStaticSets->fStrictDefaultGroupingSeparators;
- } else {
- groupingSet = fStaticSets->fDefaultGroupingSeparators;
- }
- }
-
- // We need to test groupingChar and decimalChar separately from groupingSet and decimalSet, if the sets are even initialized.
- // If sawDecimal is TRUE, only consider sawDecimalChar and NOT decimalSet
- // If a character matches decimalSet, don't consider it to be a member of the groupingSet.
-
- // We have to track digitCount ourselves, because digits.fCount will
- // pin when the maximum allowable digits is reached.
- int32_t digitCount = 0;
- int32_t integerDigitCount = 0;
-
- for (; position < textLength; )
- {
- UChar32 ch = text.char32At(position);
-
- /* We recognize all digit ranges, not only the Latin digit range
- * '0'..'9'. We do so by using the Character.digit() method,
- * which converts a valid Unicode digit to the range 0..9.
- *
- * The character 'ch' may be a digit. If so, place its value
- * from 0 to 9 in 'digit'. First try using the locale digit,
- * which may or MAY NOT be a standard Unicode digit range. If
- * this fails, try using the standard Unicode digit ranges by
- * calling Character.digit(). If this also fails, digit will
- * have a value outside the range 0..9.
- */
- digit = ch - zero;
- if (digit < 0 || digit > 9)
- {
- digit = u_charDigitValue(ch);
- }
-
- // As a last resort, look through the localized digits if the zero digit
- // is not a "standard" Unicode digit.
- if ( (digit < 0 || digit > 9) && u_charDigitValue(zero) != 0) {
- digit = 0;
- if ( fImpl->getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)(DecimalFormatSymbols::kZeroDigitSymbol)).char32At(0) == ch ) {
- break;
- }
- for (digit = 1 ; digit < 10 ; digit++ ) {
- if ( fImpl->getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)(DecimalFormatSymbols::kOneDigitSymbol+digit-1)).char32At(0) == ch ) {
- break;
- }
- }
- }
-
- if (digit >= 0 && digit <= 9)
- {
- if (strictParse && backup != -1) {
- // comma followed by digit, so group before comma is a
- // secondary group. If there was a group separator
- // before that, the group must == the secondary group
- // length, else it can be <= the the secondary group
- // length.
- if ((lastGroup != -1 && currGroup - lastGroup != gs2) ||
- (lastGroup == -1 && digitCount - 1 > gs2)) {
- strictFail = TRUE;
- break;
- }
-
- lastGroup = currGroup;
- }
-
- // Cancel out backup setting (see grouping handler below)
- currGroup = -1;
- backup = -1;
- sawDigit = TRUE;
-
- // Note: this will append leading zeros
- parsedNum.append((char)(digit + '0'), err);
-
- // count any digit that's not a leading zero
- if (digit > 0 || digitCount > 0 || sawDecimal) {
- digitCount += 1;
-
- // count any integer digit that's not a leading zero
- if (! sawDecimal) {
- integerDigitCount += 1;
- }
- }
-
- position += U16_LENGTH(ch);
- }
- else if (groupingStringLength > 0 &&
- matchGrouping(groupingChar, sawGrouping, sawGroupingChar, groupingSet,
- decimalChar, decimalSet,
- ch) && groupingUsed)
- {
- if (sawDecimal) {
- break;
- }
-
- if (strictParse) {
- if ((!sawDigit || backup != -1)) {
- // leading group, or two group separators in a row
- strictFail = TRUE;
- break;
- }
- }
-
- // Ignore grouping characters, if we are using them, but require
- // that they be followed by a digit. Otherwise we backup and
- // reprocess them.
- currGroup = digitCount;
- backup = position;
- position += groupingStringLength;
- sawGrouping=TRUE;
- // Once we see a grouping character, we only accept that grouping character from then on.
- sawGroupingChar=ch;
- }
- else if (matchDecimal(decimalChar,sawDecimal,sawDecimalChar, decimalSet, ch))
- {
- if (strictParse) {
- if (backup != -1 ||
- (lastGroup != -1 && digitCount - lastGroup != fImpl->fEffGrouping.fGrouping)) {
- strictFail = TRUE;
- break;
- }
- }
-
- // If we're only parsing integers, or if we ALREADY saw the
- // decimal, then don't parse this one.
- if (isParseIntegerOnly() || sawDecimal) {
- break;
- }
-
- parsedNum.append('.', err);
- position += decimalStringLength;
- sawDecimal = TRUE;
- // Once we see a decimal character, we only accept that decimal character from then on.
- sawDecimalChar=ch;
- // decimalSet is considered to consist of (ch,ch)
- }
- else {
-
- if(!fBoolFlags.contains(UNUM_PARSE_NO_EXPONENT) || // don't parse if this is set unless..
- isScientificNotation()) { // .. it's an exponent format - ignore setting and parse anyways
- const UnicodeString *tmp;
- tmp = &fImpl->getConstSymbol(DecimalFormatSymbols::kExponentialSymbol);
- // TODO: CASE
- if (!text.caseCompare(position, tmp->length(), *tmp, U_FOLD_CASE_DEFAULT)) // error code is set below if !sawDigit
- {
- // Parse sign, if present
- int32_t pos = position + tmp->length();
- char exponentSign = '+';
-
- if (pos < textLength)
- {
- tmp = &fImpl->getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
- if (!text.compare(pos, tmp->length(), *tmp))
- {
- pos += tmp->length();
- }
- else {
- tmp = &fImpl->getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
- if (!text.compare(pos, tmp->length(), *tmp))
- {
- exponentSign = '-';
- pos += tmp->length();
- }
- }
- }
-
- UBool sawExponentDigit = FALSE;
- while (pos < textLength) {
- ch = text.char32At(pos);
- digit = ch - zero;
-
- if (digit < 0 || digit > 9) {
- digit = u_charDigitValue(ch);
- }
- if (0 <= digit && digit <= 9) {
- if (!sawExponentDigit) {
- parsedNum.append('E', err);
- parsedNum.append(exponentSign, err);
- sawExponentDigit = TRUE;
- }
- pos += U16_LENGTH(ch);
- parsedNum.append((char)(digit + '0'), err);
- } else {
- break;
- }
- }
-
- if (sawExponentDigit) {
- position = pos; // Advance past the exponent
- }
-
- break; // Whether we fail or succeed, we exit this loop
- } else {
- break;
- }
- } else { // not parsing exponent
- break;
- }
- }
- }
-
- // if we didn't see a decimal and it is required, check to see if the pattern had one
- if(!sawDecimal && isDecimalPatternMatchRequired())
- {
- if(formatPattern.indexOf(kPatternDecimalSeparator) != -1)
- {
- parsePosition.setIndex(oldStart);
- parsePosition.setErrorIndex(position);
- debug("decimal point match required fail!");
- return FALSE;
- }
- }
-
- if (backup != -1)
- {
- position = backup;
- }
-
- if (strictParse && !sawDecimal) {
- if (lastGroup != -1 && digitCount - lastGroup != fImpl->fEffGrouping.fGrouping) {
- strictFail = TRUE;
- }
- }
+UnicodeString&
+DecimalFormat::format(double number, UnicodeString& appendTo, FieldPositionIterator* posIter,
+ UErrorCode& status) const {
+ if (posIter == nullptr && fastFormatDouble(number, appendTo)) {
+ return appendTo;
+ }
+ FormattedNumber output = fields->formatter->formatDouble(number, status);
+ fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
+ auto appendable = UnicodeStringAppendable(appendTo);
+ output.appendTo(appendable);
+ return appendTo;
+}
- if (strictFail) {
- // only set with strictParse and a grouping separator error
+UnicodeString& DecimalFormat::format(int32_t number, UnicodeString& appendTo, FieldPosition& pos) const {
+ return format(static_cast (number), appendTo, pos);
+}
- parsePosition.setIndex(oldStart);
- parsePosition.setErrorIndex(position);
- debug("strictFail!");
- return FALSE;
- }
+UnicodeString& DecimalFormat::format(int32_t number, UnicodeString& appendTo, FieldPosition& pos,
+ UErrorCode& status) const {
+ return format(static_cast (number), appendTo, pos, status);
+}
- // If there was no decimal point we have an integer
+UnicodeString&
+DecimalFormat::format(int32_t number, UnicodeString& appendTo, FieldPositionIterator* posIter,
+ UErrorCode& status) const {
+ return format(static_cast (number), appendTo, posIter, status);
+}
- // If none of the text string was recognized. For example, parse
- // "x" with pattern "#0.00" (return index and error index both 0)
- // parse "$" with pattern "$#0.00". (return index 0 and error index
- // 1).
- if (!sawDigit && digitCount == 0) {
-#ifdef FMT_DEBUG
- debug("none of text rec");
- printf("position=%d\n",position);
-#endif
- parsePosition.setIndex(oldStart);
- parsePosition.setErrorIndex(oldStart);
- return FALSE;
- }
+UnicodeString& DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPosition& pos) const {
+ if (pos.getField() == FieldPosition::DONT_CARE && fastFormatInt64(number, appendTo)) {
+ return appendTo;
}
+ UErrorCode localStatus = U_ZERO_ERROR;
+ FormattedNumber output = fields->formatter->formatInt(number, localStatus);
+ fieldPositionHelper(output, pos, appendTo.length(), localStatus);
+ auto appendable = UnicodeStringAppendable(appendTo);
+ output.appendTo(appendable);
+ return appendTo;
+}
- // Match padding before suffix
- if (formatWidth > 0 && fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforeSuffix) {
- position = skipPadding(text, position);
+UnicodeString& DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPosition& pos,
+ UErrorCode& status) const {
+ if (pos.getField() == FieldPosition::DONT_CARE && fastFormatInt64(number, appendTo)) {
+ return appendTo;
}
+ FormattedNumber output = fields->formatter->formatInt(number, status);
+ fieldPositionHelper(output, pos, appendTo.length(), status);
+ auto appendable = UnicodeStringAppendable(appendTo);
+ output.appendTo(appendable);
+ return appendTo;
+}
- int32_t posSuffixMatch = -1, negSuffixMatch = -1;
-
- // Match positive and negative suffixes; prefer longest match.
- if (posMatch >= 0 || (!strictParse && negMatch < 0)) {
- posSuffixMatch = compareAffix(text, position, FALSE, FALSE, posSuffix, complexCurrencyParsing, type, currency);
- }
- if (negMatch >= 0) {
- negSuffixMatch = compareAffix(text, position, TRUE, FALSE, negSuffix, complexCurrencyParsing, type, currency);
- }
- if (posSuffixMatch >= 0 && negSuffixMatch >= 0) {
- if (posSuffixMatch > negSuffixMatch) {
- negSuffixMatch = -1;
- } else if (negSuffixMatch > posSuffixMatch) {
- posSuffixMatch = -1;
- }
+UnicodeString&
+DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPositionIterator* posIter,
+ UErrorCode& status) const {
+ if (posIter == nullptr && fastFormatInt64(number, appendTo)) {
+ return appendTo;
}
+ FormattedNumber output = fields->formatter->formatInt(number, status);
+ fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
+ auto appendable = UnicodeStringAppendable(appendTo);
+ output.appendTo(appendable);
+ return appendTo;
+}
- // Fail if neither or both
- if (strictParse && ((posSuffixMatch >= 0) == (negSuffixMatch >= 0))) {
- parsePosition.setErrorIndex(position);
- debug("neither or both");
- return FALSE;
- }
+UnicodeString&
+DecimalFormat::format(StringPiece number, UnicodeString& appendTo, FieldPositionIterator* posIter,
+ UErrorCode& status) const {
+ FormattedNumber output = fields->formatter->formatDecimal(number, status);
+ fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
+ auto appendable = UnicodeStringAppendable(appendTo);
+ output.appendTo(appendable);
+ return appendTo;
+}
- position += (posSuffixMatch >= 0 ? posSuffixMatch : (negSuffixMatch >= 0 ? negSuffixMatch : 0));
+UnicodeString& DecimalFormat::format(const DecimalQuantity& number, UnicodeString& appendTo,
+ FieldPositionIterator* posIter, UErrorCode& status) const {
+ FormattedNumber output = fields->formatter->formatDecimalQuantity(number, status);
+ fieldPositionIteratorHelper(output, posIter, appendTo.length(), status);
+ auto appendable = UnicodeStringAppendable(appendTo);
+ output.appendTo(appendable);
+ return appendTo;
+}
- // Match padding before suffix
- if (formatWidth > 0 && fImpl->fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterSuffix) {
- position = skipPadding(text, position);
+UnicodeString&
+DecimalFormat::format(const DecimalQuantity& number, UnicodeString& appendTo, FieldPosition& pos,
+ UErrorCode& status) const {
+ FormattedNumber output = fields->formatter->formatDecimalQuantity(number, status);
+ fieldPositionHelper(output, pos, appendTo.length(), status);
+ auto appendable = UnicodeStringAppendable(appendTo);
+ output.appendTo(appendable);
+ return appendTo;
+}
+
+void DecimalFormat::parse(const UnicodeString& text, Formattable& output,
+ ParsePosition& parsePosition) const {
+ if (parsePosition.getIndex() < 0 || parsePosition.getIndex() >= text.length()) {
+ return;
}
- parsePosition.setIndex(position);
-
- parsedNum.data()[0] = (posSuffixMatch >= 0 || (!strictParse && negMatch < 0 && negSuffixMatch < 0)) ? '+' : '-';
-#ifdef FMT_DEBUG
-printf("PP -> %d, SLOW = [%s]! pp=%d, os=%d, err=%s\n", position, parsedNum.data(), parsePosition.getIndex(),oldStart,u_errorName(err));
-#endif
- } /* end SLOW parse */
- if(parsePosition.getIndex() == oldStart)
- {
-#ifdef FMT_DEBUG
- printf(" PP didnt move, err\n");
-#endif
- parsePosition.setErrorIndex(position);
- return FALSE;
- }
-#if UCONFIG_HAVE_PARSEALLINPUT
- else if (fParseAllInput==UNUM_YES&&parsePosition.getIndex()!=textLength)
- {
-#ifdef FMT_DEBUG
- printf(" PP didnt consume all (UNUM_YES), err\n");
-#endif
- parsePosition.setErrorIndex(position);
- return FALSE;
- }
-#endif
- // uint32_t bits = (fastParseOk?kFastpathOk:0) |
- // (fastParseHadDecimal?0:kNoDecimal);
- //printf("FPOK=%d, FPHD=%d, bits=%08X\n", fastParseOk, fastParseHadDecimal, bits);
- digits.set(parsedNum.toStringPiece(),
- err,
- 0//bits
- );
-
- if (U_FAILURE(err)) {
-#ifdef FMT_DEBUG
- printf(" err setting %s\n", u_errorName(err));
-#endif
- parsePosition.setErrorIndex(position);
- return FALSE;
- }
-
- // check if we missed a required decimal point
- if(fastParseOk && isDecimalPatternMatchRequired())
- {
- if(formatPattern.indexOf(kPatternDecimalSeparator) != -1)
- {
- parsePosition.setIndex(oldStart);
- parsePosition.setErrorIndex(position);
- debug("decimal point match required fail!");
- return FALSE;
- }
+ ErrorCode status;
+ ParsedNumber result;
+ // Note: if this is a currency instance, currencies will be matched despite the fact that we are not in the
+ // parseCurrency method (backwards compatibility)
+ int32_t startIndex = parsePosition.getIndex();
+ const NumberParserImpl* parser = getParser(status);
+ if (U_FAILURE(status)) { return; }
+ parser->parse(text, startIndex, true, result, status);
+ // TODO: Do we need to check for fImpl->properties->parseAllInput (UCONFIG_HAVE_PARSEALLINPUT) here?
+ if (result.success()) {
+ parsePosition.setIndex(result.charEnd);
+ result.populateFormattable(output, parser->getParseFlags());
+ } else {
+ parsePosition.setErrorIndex(startIndex + result.charEnd);
}
+}
-
- return TRUE;
-}
-
-/**
- * Starting at position, advance past a run of pad characters, if any.
- * Return the index of the first character after position that is not a pad
- * character. Result is >= position.
- */
-int32_t DecimalFormat::skipPadding(const UnicodeString& text, int32_t position) const {
- int32_t padLen = U16_LENGTH(fImpl->fAffixes.fPadChar);
- while (position < text.length() &&
- text.char32At(position) == fImpl->fAffixes.fPadChar) {
- position += padLen;
- }
- return position;
-}
-
-/**
- * Return the length matched by the given affix, or -1 if none.
- * Runs of white space in the affix, match runs of white space in
- * the input. Pattern white space and input white space are
- * determined differently; see code.
- * @param text input text
- * @param pos offset into input at which to begin matching
- * @param isNegative
- * @param isPrefix
- * @param affixPat affix pattern used for currency affix comparison.
- * @param complexCurrencyParsing whether it is currency parsing or not
- * @param type the currency type to parse against, LONG_NAME only or not.
- * @param currency return value for parsed currency, for generic
- * currency parsing mode, or null for normal parsing. In generic
- * currency parsing mode, any currency is parsed, not just the
- * currency that this formatter is set to.
- * @return length of input that matches, or -1 if match failure
- */
-int32_t DecimalFormat::compareAffix(const UnicodeString& text,
- int32_t pos,
- UBool isNegative,
- UBool isPrefix,
- const UnicodeString* affixPat,
- UBool complexCurrencyParsing,
- int8_t type,
- UChar* currency) const
-{
- const UnicodeString *patternToCompare;
- if (currency != NULL ||
- (fImpl->fMonetary && complexCurrencyParsing)) {
-
- if (affixPat != NULL) {
- return compareComplexAffix(*affixPat, text, pos, type, currency);
- }
+CurrencyAmount* DecimalFormat::parseCurrency(const UnicodeString& text, ParsePosition& parsePosition) const {
+ if (parsePosition.getIndex() < 0 || parsePosition.getIndex() >= text.length()) {
+ return nullptr;
}
- if (isNegative) {
- if (isPrefix) {
- patternToCompare = &fImpl->fAffixes.fNegativePrefix.getOtherVariant().toString();
- }
- else {
- patternToCompare = &fImpl->fAffixes.fNegativeSuffix.getOtherVariant().toString();
- }
- }
- else {
- if (isPrefix) {
- patternToCompare = &fImpl->fAffixes.fPositivePrefix.getOtherVariant().toString();
- }
- else {
- patternToCompare = &fImpl->fAffixes.fPositiveSuffix.getOtherVariant().toString();
- }
+ ErrorCode status;
+ ParsedNumber result;
+ // Note: if this is a currency instance, currencies will be matched despite the fact that we are not in the
+ // parseCurrency method (backwards compatibility)
+ int32_t startIndex = parsePosition.getIndex();
+ const NumberParserImpl* parser = getCurrencyParser(status);
+ if (U_FAILURE(status)) { return nullptr; }
+ parser->parse(text, startIndex, true, result, status);
+ // TODO: Do we need to check for fImpl->properties->parseAllInput (UCONFIG_HAVE_PARSEALLINPUT) here?
+ if (result.success()) {
+ parsePosition.setIndex(result.charEnd);
+ Formattable formattable;
+ result.populateFormattable(formattable, parser->getParseFlags());
+ return new CurrencyAmount(formattable, result.currencyCode, status);
+ } else {
+ parsePosition.setErrorIndex(startIndex + result.charEnd);
+ return nullptr;
}
- return compareSimpleAffix(*patternToCompare, text, pos, isLenient());
}
-UBool DecimalFormat::equalWithSignCompatibility(UChar32 lhs, UChar32 rhs) const {
- if (lhs == rhs) {
- return TRUE;
- }
- U_ASSERT(fStaticSets != NULL); // should already be loaded
- const UnicodeSet *minusSigns = fStaticSets->fMinusSigns;
- const UnicodeSet *plusSigns = fStaticSets->fPlusSigns;
- return (minusSigns->contains(lhs) && minusSigns->contains(rhs)) ||
- (plusSigns->contains(lhs) && plusSigns->contains(rhs));
+const DecimalFormatSymbols* DecimalFormat::getDecimalFormatSymbols(void) const {
+ return fields->symbols.getAlias();
}
-// check for LRM 0x200E, RLM 0x200F, ALM 0x061C
-#define IS_BIDI_MARK(c) (c==0x200E || c==0x200F || c==0x061C)
+void DecimalFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsToAdopt) {
+ if (symbolsToAdopt == nullptr) {
+ return; // do not allow caller to set fields->symbols to NULL
+ }
+ fields->symbols.adoptInstead(symbolsToAdopt);
+ touchNoError();
+}
-#define TRIM_BUFLEN 32
-UnicodeString& DecimalFormat::trimMarksFromAffix(const UnicodeString& affix, UnicodeString& trimmedAffix) {
- UChar trimBuf[TRIM_BUFLEN];
- int32_t affixLen = affix.length();
- int32_t affixPos, trimLen = 0;
+void DecimalFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols) {
+ fields->symbols.adoptInstead(new DecimalFormatSymbols(symbols));
+ touchNoError();
+}
- for (affixPos = 0; affixPos < affixLen; affixPos++) {
- UChar c = affix.charAt(affixPos);
- if (!IS_BIDI_MARK(c)) {
- if (trimLen < TRIM_BUFLEN) {
- trimBuf[trimLen++] = c;
- } else {
- trimLen = 0;
- break;
- }
- }
- }
- return (trimLen > 0)? trimmedAffix.setTo(trimBuf, trimLen): trimmedAffix.setTo(affix);
-}
-
-/**
- * Return the length matched by the given affix, or -1 if none.
- * Runs of white space in the affix, match runs of white space in
- * the input. Pattern white space and input white space are
- * determined differently; see code.
- * @param affix pattern string, taken as a literal
- * @param input input text
- * @param pos offset into input at which to begin matching
- * @return length of input that matches, or -1 if match failure
- */
-int32_t DecimalFormat::compareSimpleAffix(const UnicodeString& affix,
- const UnicodeString& input,
- int32_t pos,
- UBool lenient) const {
- int32_t start = pos;
- UnicodeString trimmedAffix;
- // For more efficiency we should keep lazily-created trimmed affixes around in
- // instance variables instead of trimming each time they are used (the next step)
- trimMarksFromAffix(affix, trimmedAffix);
- UChar32 affixChar = trimmedAffix.char32At(0);
- int32_t affixLength = trimmedAffix.length();
- int32_t inputLength = input.length();
- int32_t affixCharLength = U16_LENGTH(affixChar);
- UnicodeSet *affixSet;
- UErrorCode status = U_ZERO_ERROR;
-
- U_ASSERT(fStaticSets != NULL); // should already be loaded
+const CurrencyPluralInfo* DecimalFormat::getCurrencyPluralInfo(void) const {
+ return fields->properties->currencyPluralInfo.fPtr.getAlias();
+}
- if (U_FAILURE(status)) {
- return -1;
- }
- if (!lenient) {
- affixSet = fStaticSets->fStrictDashEquivalents;
-
- // If the trimmedAffix is exactly one character long and that character
- // is in the dash set and the very next input character is also
- // in the dash set, return a match.
- if (affixCharLength == affixLength && affixSet->contains(affixChar)) {
- UChar32 ic = input.char32At(pos);
- if (affixSet->contains(ic)) {
- pos += U16_LENGTH(ic);
- pos = skipBidiMarks(input, pos); // skip any trailing bidi marks
- return pos - start;
- }
- }
+void DecimalFormat::adoptCurrencyPluralInfo(CurrencyPluralInfo* toAdopt) {
+ fields->properties->currencyPluralInfo.fPtr.adoptInstead(toAdopt);
+ touchNoError();
+}
- for (int32_t i = 0; i < affixLength; ) {
- UChar32 c = trimmedAffix.char32At(i);
- int32_t len = U16_LENGTH(c);
- if (PatternProps::isWhiteSpace(c)) {
- // We may have a pattern like: \u200F \u0020
- // and input text like: \u200F \u0020
- // Note that U+200F and U+0020 are Pattern_White_Space but only
- // U+0020 is UWhiteSpace. So we have to first do a direct
- // match of the run of Pattern_White_Space in the pattern,
- // then match any extra characters.
- UBool literalMatch = FALSE;
- while (pos < inputLength) {
- UChar32 ic = input.char32At(pos);
- if (ic == c) {
- literalMatch = TRUE;
- i += len;
- pos += len;
- if (i == affixLength) {
- break;
- }
- c = trimmedAffix.char32At(i);
- len = U16_LENGTH(c);
- if (!PatternProps::isWhiteSpace(c)) {
- break;
- }
- } else if (IS_BIDI_MARK(ic)) {
- pos ++; // just skip over this input text
- } else {
- break;
- }
- }
-
- // Advance over run in pattern
- i = skipPatternWhiteSpace(trimmedAffix, i);
-
- // Advance over run in input text
- // Must see at least one white space char in input,
- // unless we've already matched some characters literally.
- int32_t s = pos;
- pos = skipUWhiteSpace(input, pos);
- if (pos == s && !literalMatch) {
- return -1;
- }
-
- // If we skip UWhiteSpace in the input text, we need to skip it in the pattern.
- // Otherwise, the previous lines may have skipped over text (such as U+00A0) that
- // is also in the trimmedAffix.
- i = skipUWhiteSpace(trimmedAffix, i);
- } else {
- UBool match = FALSE;
- while (pos < inputLength) {
- UChar32 ic = input.char32At(pos);
- if (!match && ic == c) {
- i += len;
- pos += len;
- match = TRUE;
- } else if (IS_BIDI_MARK(ic)) {
- pos++; // just skip over this input text
- } else {
- break;
- }
- }
- if (!match) {
- return -1;
- }
- }
- }
+void DecimalFormat::setCurrencyPluralInfo(const CurrencyPluralInfo& info) {
+ if (fields->properties->currencyPluralInfo.fPtr.isNull()) {
+ fields->properties->currencyPluralInfo.fPtr.adoptInstead(info.clone());
} else {
- UBool match = FALSE;
+ *fields->properties->currencyPluralInfo.fPtr = info; // copy-assignment operator
+ }
+ touchNoError();
+}
- affixSet = fStaticSets->fDashEquivalents;
+UnicodeString& DecimalFormat::getPositivePrefix(UnicodeString& result) const {
+ ErrorCode localStatus;
+ fields->formatter->getAffixImpl(true, false, result, localStatus);
+ return result;
+}
- if (affixCharLength == affixLength && affixSet->contains(affixChar)) {
- pos = skipUWhiteSpaceAndMarks(input, pos);
- UChar32 ic = input.char32At(pos);
+void DecimalFormat::setPositivePrefix(const UnicodeString& newValue) {
+ if (newValue == fields->properties->positivePrefix) { return; }
+ fields->properties->positivePrefix = newValue;
+ touchNoError();
+}
- if (affixSet->contains(ic)) {
- pos += U16_LENGTH(ic);
- pos = skipBidiMarks(input, pos);
- return pos - start;
- }
- }
+UnicodeString& DecimalFormat::getNegativePrefix(UnicodeString& result) const {
+ ErrorCode localStatus;
+ fields->formatter->getAffixImpl(true, true, result, localStatus);
+ return result;
+}
- for (int32_t i = 0; i < affixLength; )
- {
- //i = skipRuleWhiteSpace(trimmedAffix, i);
- i = skipUWhiteSpace(trimmedAffix, i);
- pos = skipUWhiteSpaceAndMarks(input, pos);
+void DecimalFormat::setNegativePrefix(const UnicodeString& newValue) {
+ if (newValue == fields->properties->negativePrefix) { return; }
+ fields->properties->negativePrefix = newValue;
+ touchNoError();
+}
- if (i >= affixLength || pos >= inputLength) {
- break;
- }
+UnicodeString& DecimalFormat::getPositiveSuffix(UnicodeString& result) const {
+ ErrorCode localStatus;
+ fields->formatter->getAffixImpl(false, false, result, localStatus);
+ return result;
+}
- UChar32 c = trimmedAffix.char32At(i);
- UChar32 ic = input.char32At(pos);
+void DecimalFormat::setPositiveSuffix(const UnicodeString& newValue) {
+ if (newValue == fields->properties->positiveSuffix) { return; }
+ fields->properties->positiveSuffix = newValue;
+ touchNoError();
+}
- if (!equalWithSignCompatibility(ic, c)) {
- return -1;
- }
+UnicodeString& DecimalFormat::getNegativeSuffix(UnicodeString& result) const {
+ ErrorCode localStatus;
+ fields->formatter->getAffixImpl(false, true, result, localStatus);
+ return result;
+}
- match = TRUE;
- i += U16_LENGTH(c);
- pos += U16_LENGTH(ic);
- pos = skipBidiMarks(input, pos);
- }
+void DecimalFormat::setNegativeSuffix(const UnicodeString& newValue) {
+ if (newValue == fields->properties->negativeSuffix) { return; }
+ fields->properties->negativeSuffix = newValue;
+ touchNoError();
+}
- if (affixLength > 0 && ! match) {
- return -1;
- }
- }
- return pos - start;
+UBool DecimalFormat::isSignAlwaysShown() const {
+ return fields->properties->signAlwaysShown;
}
-/**
- * Skip over a run of zero or more Pattern_White_Space characters at
- * pos in text.
- */
-int32_t DecimalFormat::skipPatternWhiteSpace(const UnicodeString& text, int32_t pos) {
- const UChar* s = text.getBuffer();
- return (int32_t)(PatternProps::skipWhiteSpace(s + pos, text.length() - pos) - s);
+void DecimalFormat::setSignAlwaysShown(UBool value) {
+ if (UBOOL_TO_BOOL(value) == fields->properties->signAlwaysShown) { return; }
+ fields->properties->signAlwaysShown = value;
+ touchNoError();
}
-/**
- * Skip over a run of zero or more isUWhiteSpace() characters at pos
- * in text.
- */
-int32_t DecimalFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) {
- while (pos < text.length()) {
- UChar32 c = text.char32At(pos);
- if (!u_isUWhiteSpace(c)) {
- break;
- }
- pos += U16_LENGTH(c);
+int32_t DecimalFormat::getMultiplier(void) const {
+ if (fields->properties->multiplier != 1) {
+ return fields->properties->multiplier;
+ } else if (fields->properties->magnitudeMultiplier != 0) {
+ return static_cast(uprv_pow10(fields->properties->magnitudeMultiplier));
+ } else {
+ return 1;
}
- return pos;
}
-/**
- * Skip over a run of zero or more isUWhiteSpace() characters or bidi marks at pos
- * in text.
- */
-int32_t DecimalFormat::skipUWhiteSpaceAndMarks(const UnicodeString& text, int32_t pos) {
- while (pos < text.length()) {
- UChar32 c = text.char32At(pos);
- if (!u_isUWhiteSpace(c) && !IS_BIDI_MARK(c)) { // u_isUWhiteSpace doesn't include LRM,RLM,ALM
- break;
- }
- pos += U16_LENGTH(c);
+void DecimalFormat::setMultiplier(int32_t multiplier) {
+ if (multiplier == 0) {
+ multiplier = 1; // one being the benign default value for a multiplier.
}
- return pos;
-}
-/**
- * Skip over a run of zero or more bidi marks at pos in text.
- */
-int32_t DecimalFormat::skipBidiMarks(const UnicodeString& text, int32_t pos) {
- while (pos < text.length()) {
- UChar c = text.charAt(pos);
- if (!IS_BIDI_MARK(c)) {
+ // Try to convert to a magnitude multiplier first
+ int delta = 0;
+ int value = multiplier;
+ while (value != 1) {
+ delta++;
+ int temp = value / 10;
+ if (temp * 10 != value) {
+ delta = -1;
break;
}
- pos++;
- }
- return pos;
-}
-
-/**
- * Return the length matched by the given affix, or -1 if none.
- * @param affixPat pattern string
- * @param input input text
- * @param pos offset into input at which to begin matching
- * @param type the currency type to parse against, LONG_NAME only or not.
- * @param currency return value for parsed currency, for generic
- * currency parsing mode, or null for normal parsing. In generic
- * currency parsing mode, any currency is parsed, not just the
- * currency that this formatter is set to.
- * @return length of input that matches, or -1 if match failure
- */
-int32_t DecimalFormat::compareComplexAffix(const UnicodeString& affixPat,
- const UnicodeString& text,
- int32_t pos,
- int8_t type,
- UChar* currency) const
-{
- int32_t start = pos;
- U_ASSERT(currency != NULL || fImpl->fMonetary);
-
- for (int32_t i=0;
- i= 0; ) {
- UChar32 c = affixPat.char32At(i);
- i += U16_LENGTH(c);
-
- if (c == kQuote) {
- U_ASSERT(i <= affixPat.length());
- c = affixPat.char32At(i);
- i += U16_LENGTH(c);
-
- const UnicodeString* affix = NULL;
-
- switch (c) {
- case kCurrencySign: {
- // since the currency names in choice format is saved
- // the same way as other currency names,
- // do not need to do currency choice parsing here.
- // the general currency parsing parse against all names,
- // including names in choice format.
- UBool intl = igetLocale().getName();
- ParsePosition ppos(pos);
- UChar curr[4];
- UErrorCode ec = U_ZERO_ERROR;
- // Delegate parse of display name => ISO code to Currency
- uprv_parseCurrency(loc, text, ppos, type, curr, ec);
-
- // If parse succeeds, populate currency[0]
- if (U_SUCCESS(ec) && ppos.getIndex() != pos) {
- if (currency) {
- u_strcpy(currency, curr);
- } else {
- // The formatter is currency-style but the client has not requested
- // the value of the parsed currency. In this case, if that value does
- // not match the formatter's current value, then the parse fails.
- UChar effectiveCurr[4];
- getEffectiveCurrency(effectiveCurr, ec);
- if ( U_FAILURE(ec) || u_strncmp(curr,effectiveCurr,4) != 0 ) {
- pos = -1;
- continue;
- }
- }
- pos = ppos.getIndex();
- } else if (!isLenient()){
- pos = -1;
- }
- continue;
- }
- case kPatternPercent:
- affix = &fImpl->getConstSymbol(DecimalFormatSymbols::kPercentSymbol);
- break;
- case kPatternPerMill:
- affix = &fImpl->getConstSymbol(DecimalFormatSymbols::kPerMillSymbol);
- break;
- case kPatternPlus:
- affix = &fImpl->getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
- break;
- case kPatternMinus:
- affix = &fImpl->getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
- break;
- default:
- // fall through to affix!=0 test, which will fail
- break;
- }
-
- if (affix != NULL) {
- pos = match(text, pos, *affix);
- continue;
- }
- }
-
- pos = match(text, pos, c);
- if (PatternProps::isWhiteSpace(c)) {
- i = skipPatternWhiteSpace(affixPat, i);
- }
+ value = temp;
}
- return pos - start;
-}
-
-/**
- * Match a single character at text[pos] and return the index of the
- * next character upon success. Return -1 on failure. If
- * ch is a Pattern_White_Space then match a run of white space in text.
- */
-int32_t DecimalFormat::match(const UnicodeString& text, int32_t pos, UChar32 ch) {
- if (PatternProps::isWhiteSpace(ch)) {
- // Advance over run of white space in input text
- // Must see at least one white space char in input
- int32_t s = pos;
- pos = skipPatternWhiteSpace(text, pos);
- if (pos == s) {
- return -1;
- }
- return pos;
- }
- return (pos >= 0 && text.char32At(pos) == ch) ?
- (pos + U16_LENGTH(ch)) : -1;
-}
-
-/**
- * Match a string at text[pos] and return the index of the next
- * character upon success. Return -1 on failure. Match a run of
- * white space in str with a run of white space in text.
- */
-int32_t DecimalFormat::match(const UnicodeString& text, int32_t pos, const UnicodeString& str) {
- for (int32_t i=0; i= 0; ) {
- UChar32 ch = str.char32At(i);
- i += U16_LENGTH(ch);
- if (PatternProps::isWhiteSpace(ch)) {
- i = skipPatternWhiteSpace(str, i);
- }
- pos = match(text, pos, ch);
- }
- return pos;
-}
-
-UBool DecimalFormat::matchSymbol(const UnicodeString &text, int32_t position, int32_t length, const UnicodeString &symbol,
- UnicodeSet *sset, UChar32 schar)
-{
- if (sset != NULL) {
- return sset->contains(schar);
- }
-
- return text.compare(position, length, symbol) == 0;
-}
-
-UBool DecimalFormat::matchDecimal(UChar32 symbolChar,
- UBool sawDecimal, UChar32 sawDecimalChar,
- const UnicodeSet *sset, UChar32 schar) {
- if(sawDecimal) {
- return schar==sawDecimalChar;
- } else if(schar==symbolChar) {
- return TRUE;
- } else if(sset!=NULL) {
- return sset->contains(schar);
- } else {
- return FALSE;
- }
-}
-
-UBool DecimalFormat::matchGrouping(UChar32 groupingChar,
- UBool sawGrouping, UChar32 sawGroupingChar,
- const UnicodeSet *sset,
- UChar32 /*decimalChar*/, const UnicodeSet *decimalSet,
- UChar32 schar) {
- if(sawGrouping) {
- return schar==sawGroupingChar; // previously found
- } else if(schar==groupingChar) {
- return TRUE; // char from symbols
- } else if(sset!=NULL) {
- return sset->contains(schar) && // in groupingSet but...
- ((decimalSet==NULL) || !decimalSet->contains(schar)); // Exclude decimalSet from groupingSet
+ if (delta != -1) {
+ fields->properties->magnitudeMultiplier = delta;
+ fields->properties->multiplier = 1;
} else {
- return FALSE;
+ fields->properties->magnitudeMultiplier = 0;
+ fields->properties->multiplier = multiplier;
}
+ touchNoError();
}
+int32_t DecimalFormat::getMultiplierScale() const {
+ return fields->properties->multiplierScale;
+}
+void DecimalFormat::setMultiplierScale(int32_t newValue) {
+ if (newValue == fields->properties->multiplierScale) { return; }
+ fields->properties->multiplierScale = newValue;
+ touchNoError();
+}
-//------------------------------------------------------------------------------
-// Gets the pointer to the localized decimal format symbols
+double DecimalFormat::getRoundingIncrement(void) const {
+ return fields->exportedProperties->roundingIncrement;
+}
-const DecimalFormatSymbols*
-DecimalFormat::getDecimalFormatSymbols() const
-{
- return &fImpl->getDecimalFormatSymbols();
+void DecimalFormat::setRoundingIncrement(double newValue) {
+ if (newValue == fields->properties->roundingIncrement) { return; }
+ fields->properties->roundingIncrement = newValue;
+ touchNoError();
}
-//------------------------------------------------------------------------------
-// De-owning the current localized symbols and adopt the new symbols.
+ERoundingMode DecimalFormat::getRoundingMode(void) const {
+ // UNumberFormatRoundingMode and ERoundingMode have the same values.
+ return static_cast(fields->exportedProperties->roundingMode.getNoError());
+}
-void
-DecimalFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsToAdopt)
-{
- if (symbolsToAdopt == NULL) {
- return; // do not allow caller to set fSymbols to NULL
+void DecimalFormat::setRoundingMode(ERoundingMode roundingMode) {
+ auto uRoundingMode = static_cast(roundingMode);
+ if (!fields->properties->roundingMode.isNull() && uRoundingMode == fields->properties->roundingMode.getNoError()) {
+ return;
}
- fImpl->adoptDecimalFormatSymbols(symbolsToAdopt);
+ NumberFormat::setMaximumIntegerDigits(roundingMode); // to set field for compatibility
+ fields->properties->roundingMode = uRoundingMode;
+ touchNoError();
}
-//------------------------------------------------------------------------------
-// Setting the symbols is equlivalent to adopting a newly created localized
-// symbols.
-void
-DecimalFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols)
-{
- adoptDecimalFormatSymbols(new DecimalFormatSymbols(symbols));
+int32_t DecimalFormat::getFormatWidth(void) const {
+ return fields->properties->formatWidth;
}
-
-const CurrencyPluralInfo*
-DecimalFormat::getCurrencyPluralInfo(void) const
-{
- return fCurrencyPluralInfo;
+void DecimalFormat::setFormatWidth(int32_t width) {
+ if (width == fields->properties->formatWidth) { return; }
+ fields->properties->formatWidth = width;
+ touchNoError();
}
-
-void
-DecimalFormat::adoptCurrencyPluralInfo(CurrencyPluralInfo* toAdopt)
-{
- if (toAdopt != NULL) {
- delete fCurrencyPluralInfo;
- fCurrencyPluralInfo = toAdopt;
- // re-set currency affix patterns and currency affixes.
- if (fImpl->fMonetary) {
- UErrorCode status = U_ZERO_ERROR;
- if (fAffixPatternsForCurrency) {
- deleteHashForAffixPattern();
- }
- setupCurrencyAffixPatterns(status);
- }
+UnicodeString DecimalFormat::getPadCharacterString() const {
+ if (fields->properties->padString.isBogus()) {
+ // Readonly-alias the static string kFallbackPaddingString
+ return {TRUE, kFallbackPaddingString, -1};
+ } else {
+ return fields->properties->padString;
}
}
-void
-DecimalFormat::setCurrencyPluralInfo(const CurrencyPluralInfo& info)
-{
- adoptCurrencyPluralInfo(info.clone());
+void DecimalFormat::setPadCharacter(const UnicodeString& padChar) {
+ if (padChar == fields->properties->padString) { return; }
+ if (padChar.length() > 0) {
+ fields->properties->padString = UnicodeString(padChar.char32At(0));
+ } else {
+ fields->properties->padString.setToBogus();
+ }
+ touchNoError();
}
-
-//------------------------------------------------------------------------------
-// Gets the positive prefix of the number pattern.
-
-UnicodeString&
-DecimalFormat::getPositivePrefix(UnicodeString& result) const
-{
- return fImpl->getPositivePrefix(result);
+EPadPosition DecimalFormat::getPadPosition(void) const {
+ if (fields->properties->padPosition.isNull()) {
+ return EPadPosition::kPadBeforePrefix;
+ } else {
+ // UNumberFormatPadPosition and EPadPosition have the same values.
+ return static_cast(fields->properties->padPosition.getNoError());
+ }
}
-//------------------------------------------------------------------------------
-// Sets the positive prefix of the number pattern.
-
-void
-DecimalFormat::setPositivePrefix(const UnicodeString& newValue)
-{
- fImpl->setPositivePrefix(newValue);
+void DecimalFormat::setPadPosition(EPadPosition padPos) {
+ auto uPadPos = static_cast(padPos);
+ if (!fields->properties->padPosition.isNull() && uPadPos == fields->properties->padPosition.getNoError()) {
+ return;
+ }
+ fields->properties->padPosition = uPadPos;
+ touchNoError();
}
-//------------------------------------------------------------------------------
-// Gets the negative prefix of the number pattern.
-
-UnicodeString&
-DecimalFormat::getNegativePrefix(UnicodeString& result) const
-{
- return fImpl->getNegativePrefix(result);
+UBool DecimalFormat::isScientificNotation(void) const {
+ return fields->properties->minimumExponentDigits != -1;
}
-//------------------------------------------------------------------------------
-// Gets the negative prefix of the number pattern.
-
-void
-DecimalFormat::setNegativePrefix(const UnicodeString& newValue)
-{
- fImpl->setNegativePrefix(newValue);
+void DecimalFormat::setScientificNotation(UBool useScientific) {
+ int32_t minExp = useScientific ? 1 : -1;
+ if (fields->properties->minimumExponentDigits == minExp) { return; }
+ if (useScientific) {
+ fields->properties->minimumExponentDigits = 1;
+ } else {
+ fields->properties->minimumExponentDigits = -1;
+ }
+ touchNoError();
}
-//------------------------------------------------------------------------------
-// Gets the positive suffix of the number pattern.
-
-UnicodeString&
-DecimalFormat::getPositiveSuffix(UnicodeString& result) const
-{
- return fImpl->getPositiveSuffix(result);
+int8_t DecimalFormat::getMinimumExponentDigits(void) const {
+ return static_cast(fields->properties->minimumExponentDigits);
}
-//------------------------------------------------------------------------------
-// Sets the positive suffix of the number pattern.
-
-void
-DecimalFormat::setPositiveSuffix(const UnicodeString& newValue)
-{
- fImpl->setPositiveSuffix(newValue);
+void DecimalFormat::setMinimumExponentDigits(int8_t minExpDig) {
+ if (minExpDig == fields->properties->minimumExponentDigits) { return; }
+ fields->properties->minimumExponentDigits = minExpDig;
+ touchNoError();
}
-//------------------------------------------------------------------------------
-// Gets the negative suffix of the number pattern.
-
-UnicodeString&
-DecimalFormat::getNegativeSuffix(UnicodeString& result) const
-{
- return fImpl->getNegativeSuffix(result);
+UBool DecimalFormat::isExponentSignAlwaysShown(void) const {
+ return fields->properties->exponentSignAlwaysShown;
}
-//------------------------------------------------------------------------------
-// Sets the negative suffix of the number pattern.
-
-void
-DecimalFormat::setNegativeSuffix(const UnicodeString& newValue)
-{
- fImpl->setNegativeSuffix(newValue);
+void DecimalFormat::setExponentSignAlwaysShown(UBool expSignAlways) {
+ if (UBOOL_TO_BOOL(expSignAlways) == fields->properties->exponentSignAlwaysShown) { return; }
+ fields->properties->exponentSignAlwaysShown = expSignAlways;
+ touchNoError();
}
-//------------------------------------------------------------------------------
-// Gets the multiplier of the number pattern.
-// Multipliers are stored as decimal numbers (DigitLists) because that
-// is the most convenient for muliplying or dividing the numbers to be formatted.
-// A NULL multiplier implies one, and the scaling operations are skipped.
-
-int32_t
-DecimalFormat::getMultiplier() const
-{
- return fImpl->getMultiplier();
+int32_t DecimalFormat::getGroupingSize(void) const {
+ if (fields->properties->groupingSize < 0) {
+ return 0;
+ }
+ return fields->properties->groupingSize;
}
-//------------------------------------------------------------------------------
-// Sets the multiplier of the number pattern.
-void
-DecimalFormat::setMultiplier(int32_t newValue)
-{
- fImpl->setMultiplier(newValue);
-}
-
-/**
- * Get the rounding increment.
- * @return A positive rounding increment, or 0.0 if rounding
- * is not in effect.
- * @see #setRoundingIncrement
- * @see #getRoundingMode
- * @see #setRoundingMode
- */
-double DecimalFormat::getRoundingIncrement() const {
- return fImpl->getRoundingIncrement();
-}
-
-/**
- * Set the rounding increment. This method also controls whether
- * rounding is enabled.
- * @param newValue A positive rounding increment, or 0.0 to disable rounding.
- * Negative increments are equivalent to 0.0.
- * @see #getRoundingIncrement
- * @see #getRoundingMode
- * @see #setRoundingMode
- */
-void DecimalFormat::setRoundingIncrement(double newValue) {
- fImpl->setRoundingIncrement(newValue);
-}
-
-/**
- * Get the rounding mode.
- * @return A rounding mode
- * @see #setRoundingIncrement
- * @see #getRoundingIncrement
- * @see #setRoundingMode
- */
-DecimalFormat::ERoundingMode DecimalFormat::getRoundingMode() const {
- return fImpl->getRoundingMode();
-}
-
-/**
- * Set the rounding mode. This has no effect unless the rounding
- * increment is greater than zero.
- * @param roundingMode A rounding mode
- * @see #setRoundingIncrement
- * @see #getRoundingIncrement
- * @see #getRoundingMode
- */
-void DecimalFormat::setRoundingMode(ERoundingMode roundingMode) {
- fImpl->setRoundingMode(roundingMode);
-}
-
-/**
- * Get the width to which the output of format()
is padded.
- * @return the format width, or zero if no padding is in effect
- * @see #setFormatWidth
- * @see #getPadCharacter
- * @see #setPadCharacter
- * @see #getPadPosition
- * @see #setPadPosition
- */
-int32_t DecimalFormat::getFormatWidth() const {
- return fImpl->getFormatWidth();
-}
-
-/**
- * Set the width to which the output of format()
is padded.
- * This method also controls whether padding is enabled.
- * @param width the width to which to pad the result of
- * format()
, or zero to disable padding. A negative
- * width is equivalent to 0.
- * @see #getFormatWidth
- * @see #getPadCharacter
- * @see #setPadCharacter
- * @see #getPadPosition
- * @see #setPadPosition
- */
-void DecimalFormat::setFormatWidth(int32_t width) {
- int32_t formatWidth = (width > 0) ? width : 0;
- fImpl->setFormatWidth(formatWidth);
+void DecimalFormat::setGroupingSize(int32_t newValue) {
+ if (newValue == fields->properties->groupingSize) { return; }
+ fields->properties->groupingSize = newValue;
+ touchNoError();
}
-UnicodeString DecimalFormat::getPadCharacterString() const {
- return UnicodeString(fImpl->getPadCharacter());
+int32_t DecimalFormat::getSecondaryGroupingSize(void) const {
+ int grouping2 = fields->properties->secondaryGroupingSize;
+ if (grouping2 < 0) {
+ return 0;
+ }
+ return grouping2;
}
-void DecimalFormat::setPadCharacter(const UnicodeString &padChar) {
- UChar32 pad;
- if (padChar.length() > 0) {
- pad = padChar.char32At(0);
- }
- else {
- pad = kDefaultPad;
- }
- fImpl->setPadCharacter(pad);
-}
-
-static DecimalFormat::EPadPosition fromPadPosition(DigitAffixesAndPadding::EPadPosition padPos) {
- switch (padPos) {
- case DigitAffixesAndPadding::kPadBeforePrefix:
- return DecimalFormat::kPadBeforePrefix;
- case DigitAffixesAndPadding::kPadAfterPrefix:
- return DecimalFormat::kPadAfterPrefix;
- case DigitAffixesAndPadding::kPadBeforeSuffix:
- return DecimalFormat::kPadBeforeSuffix;
- case DigitAffixesAndPadding::kPadAfterSuffix:
- return DecimalFormat::kPadAfterSuffix;
- default:
- U_ASSERT(FALSE);
- break;
- }
- return DecimalFormat::kPadBeforePrefix;
-}
-
-/**
- * Get the position at which padding will take place. This is the location
- * at which padding will be inserted if the result of format()
- * is shorter than the format width.
- * @return the pad position, one of kPadBeforePrefix
,
- * kPadAfterPrefix
, kPadBeforeSuffix
, or
- * kPadAfterSuffix
.
- * @see #setFormatWidth
- * @see #getFormatWidth
- * @see #setPadCharacter
- * @see #getPadCharacter
- * @see #setPadPosition
- * @see #kPadBeforePrefix
- * @see #kPadAfterPrefix
- * @see #kPadBeforeSuffix
- * @see #kPadAfterSuffix
- */
-DecimalFormat::EPadPosition DecimalFormat::getPadPosition() const {
- return fromPadPosition(fImpl->getPadPosition());
-}
-
-static DigitAffixesAndPadding::EPadPosition toPadPosition(DecimalFormat::EPadPosition padPos) {
- switch (padPos) {
- case DecimalFormat::kPadBeforePrefix:
- return DigitAffixesAndPadding::kPadBeforePrefix;
- case DecimalFormat::kPadAfterPrefix:
- return DigitAffixesAndPadding::kPadAfterPrefix;
- case DecimalFormat::kPadBeforeSuffix:
- return DigitAffixesAndPadding::kPadBeforeSuffix;
- case DecimalFormat::kPadAfterSuffix:
- return DigitAffixesAndPadding::kPadAfterSuffix;
- default:
- U_ASSERT(FALSE);
- break;
- }
- return DigitAffixesAndPadding::kPadBeforePrefix;
-}
-
-/**
- * NEW
- * Set the position at which padding will take place. This is the location
- * at which padding will be inserted if the result of format()
- * is shorter than the format width. This has no effect unless padding is
- * enabled.
- * @param padPos the pad position, one of kPadBeforePrefix
,
- * kPadAfterPrefix
, kPadBeforeSuffix
, or
- * kPadAfterSuffix
.
- * @see #setFormatWidth
- * @see #getFormatWidth
- * @see #setPadCharacter
- * @see #getPadCharacter
- * @see #getPadPosition
- * @see #kPadBeforePrefix
- * @see #kPadAfterPrefix
- * @see #kPadBeforeSuffix
- * @see #kPadAfterSuffix
- */
-void DecimalFormat::setPadPosition(EPadPosition padPos) {
- fImpl->setPadPosition(toPadPosition(padPos));
-}
-
-/**
- * Return whether or not scientific notation is used.
- * @return TRUE if this object formats and parses scientific notation
- * @see #setScientificNotation
- * @see #getMinimumExponentDigits
- * @see #setMinimumExponentDigits
- * @see #isExponentSignAlwaysShown
- * @see #setExponentSignAlwaysShown
- */
-UBool DecimalFormat::isScientificNotation() const {
- return fImpl->isScientificNotation();
-}
-
-/**
- * Set whether or not scientific notation is used.
- * @param useScientific TRUE if this object formats and parses scientific
- * notation
- * @see #isScientificNotation
- * @see #getMinimumExponentDigits
- * @see #setMinimumExponentDigits
- * @see #isExponentSignAlwaysShown
- * @see #setExponentSignAlwaysShown
- */
-void DecimalFormat::setScientificNotation(UBool useScientific) {
- fImpl->setScientificNotation(useScientific);
-}
-
-/**
- * Return the minimum exponent digits that will be shown.
- * @return the minimum exponent digits that will be shown
- * @see #setScientificNotation
- * @see #isScientificNotation
- * @see #setMinimumExponentDigits
- * @see #isExponentSignAlwaysShown
- * @see #setExponentSignAlwaysShown
- */
-int8_t DecimalFormat::getMinimumExponentDigits() const {
- return fImpl->getMinimumExponentDigits();
-}
-
-/**
- * Set the minimum exponent digits that will be shown. This has no
- * effect unless scientific notation is in use.
- * @param minExpDig a value >= 1 indicating the fewest exponent digits
- * that will be shown. Values less than 1 will be treated as 1.
- * @see #setScientificNotation
- * @see #isScientificNotation
- * @see #getMinimumExponentDigits
- * @see #isExponentSignAlwaysShown
- * @see #setExponentSignAlwaysShown
- */
-void DecimalFormat::setMinimumExponentDigits(int8_t minExpDig) {
- int32_t minExponentDigits = (int8_t)((minExpDig > 0) ? minExpDig : 1);
- fImpl->setMinimumExponentDigits(minExponentDigits);
-}
-
-/**
- * Return whether the exponent sign is always shown.
- * @return TRUE if the exponent is always prefixed with either the
- * localized minus sign or the localized plus sign, false if only negative
- * exponents are prefixed with the localized minus sign.
- * @see #setScientificNotation
- * @see #isScientificNotation
- * @see #setMinimumExponentDigits
- * @see #getMinimumExponentDigits
- * @see #setExponentSignAlwaysShown
- */
-UBool DecimalFormat::isExponentSignAlwaysShown() const {
- return fImpl->isExponentSignAlwaysShown();
-}
-
-/**
- * Set whether the exponent sign is always shown. This has no effect
- * unless scientific notation is in use.
- * @param expSignAlways TRUE if the exponent is always prefixed with either
- * the localized minus sign or the localized plus sign, false if only
- * negative exponents are prefixed with the localized minus sign.
- * @see #setScientificNotation
- * @see #isScientificNotation
- * @see #setMinimumExponentDigits
- * @see #getMinimumExponentDigits
- * @see #isExponentSignAlwaysShown
- */
-void DecimalFormat::setExponentSignAlwaysShown(UBool expSignAlways) {
- fImpl->setExponentSignAlwaysShown(expSignAlways);
+void DecimalFormat::setSecondaryGroupingSize(int32_t newValue) {
+ if (newValue == fields->properties->secondaryGroupingSize) { return; }
+ fields->properties->secondaryGroupingSize = newValue;
+ touchNoError();
}
-//------------------------------------------------------------------------------
-// Gets the grouping size of the number pattern. For example, thousand or 10
-// thousand groupings.
-
-int32_t
-DecimalFormat::getGroupingSize() const
-{
- return fImpl->getGroupingSize();
+int32_t DecimalFormat::getMinimumGroupingDigits() const {
+ return fields->properties->minimumGroupingDigits;
}
-//------------------------------------------------------------------------------
-// Gets the grouping size of the number pattern.
-
-void
-DecimalFormat::setGroupingSize(int32_t newValue)
-{
- fImpl->setGroupingSize(newValue);
+void DecimalFormat::setMinimumGroupingDigits(int32_t newValue) {
+ if (newValue == fields->properties->minimumGroupingDigits) { return; }
+ fields->properties->minimumGroupingDigits = newValue;
+ touchNoError();
}
-//------------------------------------------------------------------------------
-
-int32_t
-DecimalFormat::getSecondaryGroupingSize() const
-{
- return fImpl->getSecondaryGroupingSize();
+UBool DecimalFormat::isDecimalSeparatorAlwaysShown(void) const {
+ return fields->properties->decimalSeparatorAlwaysShown;
}
-//------------------------------------------------------------------------------
-
-void
-DecimalFormat::setSecondaryGroupingSize(int32_t newValue)
-{
- fImpl->setSecondaryGroupingSize(newValue);
+void DecimalFormat::setDecimalSeparatorAlwaysShown(UBool newValue) {
+ if (UBOOL_TO_BOOL(newValue) == fields->properties->decimalSeparatorAlwaysShown) { return; }
+ fields->properties->decimalSeparatorAlwaysShown = newValue;
+ touchNoError();
}
-//------------------------------------------------------------------------------
-
-int32_t
-DecimalFormat::getMinimumGroupingDigits() const
-{
- return fImpl->getMinimumGroupingDigits();
+UBool DecimalFormat::isDecimalPatternMatchRequired(void) const {
+ return fields->properties->decimalPatternMatchRequired;
}
-//------------------------------------------------------------------------------
-
-void
-DecimalFormat::setMinimumGroupingDigits(int32_t newValue)
-{
- fImpl->setMinimumGroupingDigits(newValue);
+void DecimalFormat::setDecimalPatternMatchRequired(UBool newValue) {
+ if (UBOOL_TO_BOOL(newValue) == fields->properties->decimalPatternMatchRequired) { return; }
+ fields->properties->decimalPatternMatchRequired = newValue;
+ touchNoError();
}
-//------------------------------------------------------------------------------
-// Checks if to show the decimal separator.
-
-UBool
-DecimalFormat::isDecimalSeparatorAlwaysShown() const
-{
- return fImpl->isDecimalSeparatorAlwaysShown();
+UBool DecimalFormat::isParseNoExponent() const {
+ return fields->properties->parseNoExponent;
}
-//------------------------------------------------------------------------------
-// Sets to always show the decimal separator.
-
-void
-DecimalFormat::setDecimalSeparatorAlwaysShown(UBool newValue)
-{
- fImpl->setDecimalSeparatorAlwaysShown(newValue);
+void DecimalFormat::setParseNoExponent(UBool value) {
+ if (UBOOL_TO_BOOL(value) == fields->properties->parseNoExponent) { return; }
+ fields->properties->parseNoExponent = value;
+ touchNoError();
}
-//------------------------------------------------------------------------------
-// Checks if decimal point pattern match is required
-UBool
-DecimalFormat::isDecimalPatternMatchRequired(void) const
-{
- return static_cast(fBoolFlags.contains(UNUM_PARSE_DECIMAL_MARK_REQUIRED));
+UBool DecimalFormat::isParseCaseSensitive() const {
+ return fields->properties->parseCaseSensitive;
}
-//------------------------------------------------------------------------------
-// Checks if decimal point pattern match is required
-
-void
-DecimalFormat::setDecimalPatternMatchRequired(UBool newValue)
-{
- fBoolFlags.set(UNUM_PARSE_DECIMAL_MARK_REQUIRED, newValue);
+void DecimalFormat::setParseCaseSensitive(UBool value) {
+ if (UBOOL_TO_BOOL(value) == fields->properties->parseCaseSensitive) { return; }
+ fields->properties->parseCaseSensitive = value;
+ touchNoError();
}
-
-//------------------------------------------------------------------------------
-// Emits the pattern of this DecimalFormat instance.
-
-UnicodeString&
-DecimalFormat::toPattern(UnicodeString& result) const
-{
- return fImpl->toPattern(result);
+UBool DecimalFormat::isFormatFailIfMoreThanMaxDigits() const {
+ return fields->properties->formatFailIfMoreThanMaxDigits;
}
-//------------------------------------------------------------------------------
-// Emits the localized pattern this DecimalFormat instance.
-
-UnicodeString&
-DecimalFormat::toLocalizedPattern(UnicodeString& result) const
-{
- // toLocalizedPattern is deprecated, so we just make it the same as
- // toPattern.
- return fImpl->toPattern(result);
+void DecimalFormat::setFormatFailIfMoreThanMaxDigits(UBool value) {
+ if (UBOOL_TO_BOOL(value) == fields->properties->formatFailIfMoreThanMaxDigits) { return; }
+ fields->properties->formatFailIfMoreThanMaxDigits = value;
+ touchNoError();
}
-//------------------------------------------------------------------------------
-
-void
-DecimalFormat::applyPattern(const UnicodeString& pattern, UErrorCode& status)
-{
- if (pattern.indexOf(kCurrencySign) != -1) {
- handleCurrencySignInPattern(status);
+UnicodeString& DecimalFormat::toPattern(UnicodeString& result) const {
+ // Pull some properties from exportedProperties and others from properties
+ // to keep affix patterns intact. In particular, pull rounding properties
+ // so that CurrencyUsage is reflected properly.
+ // TODO: Consider putting this logic in number_patternstring.cpp instead.
+ ErrorCode localStatus;
+ DecimalFormatProperties tprops(*fields->properties);
+ bool useCurrency = ((!tprops.currency.isNull()) || !tprops.currencyPluralInfo.fPtr.isNull() ||
+ !tprops.currencyUsage.isNull() || AffixUtils::hasCurrencySymbols(
+ tprops.positivePrefixPattern, localStatus) || AffixUtils::hasCurrencySymbols(
+ tprops.positiveSuffixPattern, localStatus) || AffixUtils::hasCurrencySymbols(
+ tprops.negativePrefixPattern, localStatus) || AffixUtils::hasCurrencySymbols(
+ tprops.negativeSuffixPattern, localStatus));
+ if (useCurrency) {
+ tprops.minimumFractionDigits = fields->exportedProperties->minimumFractionDigits;
+ tprops.maximumFractionDigits = fields->exportedProperties->maximumFractionDigits;
+ tprops.roundingIncrement = fields->exportedProperties->roundingIncrement;
}
- fImpl->applyPattern(pattern, status);
+ result = PatternStringUtils::propertiesToPatternString(tprops, localStatus);
+ return result;
}
-//------------------------------------------------------------------------------
+UnicodeString& DecimalFormat::toLocalizedPattern(UnicodeString& result) const {
+ ErrorCode localStatus;
+ result = toPattern(result);
+ result = PatternStringUtils::convertLocalized(result, *fields->symbols, true, localStatus);
+ return result;
+}
-void
-DecimalFormat::applyPattern(const UnicodeString& pattern,
- UParseError& parseError,
- UErrorCode& status)
-{
- if (pattern.indexOf(kCurrencySign) != -1) {
- handleCurrencySignInPattern(status);
- }
- fImpl->applyPattern(pattern, parseError, status);
+void DecimalFormat::applyPattern(const UnicodeString& pattern, UParseError&, UErrorCode& status) {
+ // TODO: What is parseError for?
+ applyPattern(pattern, status);
}
-//------------------------------------------------------------------------------
-void
-DecimalFormat::applyLocalizedPattern(const UnicodeString& pattern, UErrorCode& status)
-{
- if (pattern.indexOf(kCurrencySign) != -1) {
- handleCurrencySignInPattern(status);
- }
- fImpl->applyLocalizedPattern(pattern, status);
+void DecimalFormat::applyPattern(const UnicodeString& pattern, UErrorCode& status) {
+ setPropertiesFromPattern(pattern, IGNORE_ROUNDING_NEVER, status);
+ touch(status);
}
-//------------------------------------------------------------------------------
+void DecimalFormat::applyLocalizedPattern(const UnicodeString& localizedPattern, UParseError&,
+ UErrorCode& status) {
+ // TODO: What is parseError for?
+ applyLocalizedPattern(localizedPattern, status);
+}
-void
-DecimalFormat::applyLocalizedPattern(const UnicodeString& pattern,
- UParseError& parseError,
- UErrorCode& status)
-{
- if (pattern.indexOf(kCurrencySign) != -1) {
- handleCurrencySignInPattern(status);
+void DecimalFormat::applyLocalizedPattern(const UnicodeString& localizedPattern, UErrorCode& status) {
+ if (U_SUCCESS(status)) {
+ UnicodeString pattern = PatternStringUtils::convertLocalized(
+ localizedPattern, *fields->symbols, false, status);
+ applyPattern(pattern, status);
}
- fImpl->applyLocalizedPattern(pattern, parseError, status);
}
-//------------------------------------------------------------------------------
-
-/**
- * Sets the maximum number of digits allowed in the integer portion of a
- * number.
- * @see NumberFormat#setMaximumIntegerDigits
- */
void DecimalFormat::setMaximumIntegerDigits(int32_t newValue) {
- newValue = _min(newValue, gDefaultMaxIntegerDigits);
- NumberFormat::setMaximumIntegerDigits(newValue);
- fImpl->updatePrecision();
+ if (newValue == fields->properties->maximumIntegerDigits) { return; }
+ // For backwards compatibility, conflicting min/max need to keep the most recent setting.
+ int32_t min = fields->properties->minimumIntegerDigits;
+ if (min >= 0 && min > newValue) {
+ fields->properties->minimumIntegerDigits = newValue;
+ }
+ fields->properties->maximumIntegerDigits = newValue;
+ touchNoError();
}
-/**
- * Sets the minimum number of digits allowed in the integer portion of a
- * number. This override limits the integer digit count to 309.
- * @see NumberFormat#setMinimumIntegerDigits
- */
void DecimalFormat::setMinimumIntegerDigits(int32_t newValue) {
- newValue = _min(newValue, kDoubleIntegerDigits);
- NumberFormat::setMinimumIntegerDigits(newValue);
- fImpl->updatePrecision();
+ if (newValue == fields->properties->minimumIntegerDigits) { return; }
+ // For backwards compatibility, conflicting min/max need to keep the most recent setting.
+ int32_t max = fields->properties->maximumIntegerDigits;
+ if (max >= 0 && max < newValue) {
+ fields->properties->maximumIntegerDigits = newValue;
+ }
+ fields->properties->minimumIntegerDigits = newValue;
+ touchNoError();
}
-/**
- * Sets the maximum number of digits allowed in the fraction portion of a
- * number. This override limits the fraction digit count to 340.
- * @see NumberFormat#setMaximumFractionDigits
- */
void DecimalFormat::setMaximumFractionDigits(int32_t newValue) {
- newValue = _min(newValue, kDoubleFractionDigits);
- NumberFormat::setMaximumFractionDigits(newValue);
- fImpl->updatePrecision();
+ if (newValue == fields->properties->maximumFractionDigits) { return; }
+ // For backwards compatibility, conflicting min/max need to keep the most recent setting.
+ int32_t min = fields->properties->minimumFractionDigits;
+ if (min >= 0 && min > newValue) {
+ fields->properties->minimumFractionDigits = newValue;
+ }
+ fields->properties->maximumFractionDigits = newValue;
+ touchNoError();
}
-/**
- * Sets the minimum number of digits allowed in the fraction portion of a
- * number. This override limits the fraction digit count to 340.
- * @see NumberFormat#setMinimumFractionDigits
- */
void DecimalFormat::setMinimumFractionDigits(int32_t newValue) {
- newValue = _min(newValue, kDoubleFractionDigits);
- NumberFormat::setMinimumFractionDigits(newValue);
- fImpl->updatePrecision();
+ if (newValue == fields->properties->minimumFractionDigits) { return; }
+ // For backwards compatibility, conflicting min/max need to keep the most recent setting.
+ int32_t max = fields->properties->maximumFractionDigits;
+ if (max >= 0 && max < newValue) {
+ fields->properties->maximumFractionDigits = newValue;
+ }
+ fields->properties->minimumFractionDigits = newValue;
+ touchNoError();
}
int32_t DecimalFormat::getMinimumSignificantDigits() const {
- return fImpl->getMinimumSignificantDigits();
+ return fields->exportedProperties->minimumSignificantDigits;
}
int32_t DecimalFormat::getMaximumSignificantDigits() const {
- return fImpl->getMaximumSignificantDigits();
+ return fields->exportedProperties->maximumSignificantDigits;
}
-void DecimalFormat::setMinimumSignificantDigits(int32_t min) {
- if (min < 1) {
- min = 1;
+void DecimalFormat::setMinimumSignificantDigits(int32_t value) {
+ if (value == fields->properties->minimumSignificantDigits) { return; }
+ int32_t max = fields->properties->maximumSignificantDigits;
+ if (max >= 0 && max < value) {
+ fields->properties->maximumSignificantDigits = value;
}
- // pin max sig dig to >= min
- int32_t max = _max(fImpl->fMaxSigDigits, min);
- fImpl->setMinMaxSignificantDigits(min, max);
+ fields->properties->minimumSignificantDigits = value;
+ touchNoError();
}
-void DecimalFormat::setMaximumSignificantDigits(int32_t max) {
- if (max < 1) {
- max = 1;
+void DecimalFormat::setMaximumSignificantDigits(int32_t value) {
+ if (value == fields->properties->maximumSignificantDigits) { return; }
+ int32_t min = fields->properties->minimumSignificantDigits;
+ if (min >= 0 && min > value) {
+ fields->properties->minimumSignificantDigits = value;
}
- // pin min sig dig to 1..max
- U_ASSERT(fImpl->fMinSigDigits >= 1);
- int32_t min = _min(fImpl->fMinSigDigits, max);
- fImpl->setMinMaxSignificantDigits(min, max);
+ fields->properties->maximumSignificantDigits = value;
+ touchNoError();
}
UBool DecimalFormat::areSignificantDigitsUsed() const {
- return fImpl->areSignificantDigitsUsed();
+ return fields->properties->minimumSignificantDigits != -1 || fields->properties->maximumSignificantDigits != -1;
}
void DecimalFormat::setSignificantDigitsUsed(UBool useSignificantDigits) {
- fImpl->setSignificantDigitsUsed(useSignificantDigits);
-}
-
-void DecimalFormat::setCurrency(const UChar* theCurrency, UErrorCode& ec) {
- // set the currency before compute affixes to get the right currency names
- NumberFormat::setCurrency(theCurrency, ec);
- fImpl->updateCurrency(ec);
-}
-
-void DecimalFormat::setCurrencyUsage(UCurrencyUsage newContext, UErrorCode* ec){
- fImpl->setCurrencyUsage(newContext, *ec);
-}
-
-UCurrencyUsage DecimalFormat::getCurrencyUsage() const {
- return fImpl->getCurrencyUsage();
-}
-
-// Deprecated variant with no UErrorCode parameter
-void DecimalFormat::setCurrency(const UChar* theCurrency) {
- UErrorCode ec = U_ZERO_ERROR;
- setCurrency(theCurrency, ec);
+ // These are the default values from the old implementation.
+ int32_t minSig = useSignificantDigits ? 1 : -1;
+ int32_t maxSig = useSignificantDigits ? 6 : -1;
+ if (fields->properties->minimumSignificantDigits == minSig &&
+ fields->properties->maximumSignificantDigits == maxSig) {
+ return;
+ }
+ fields->properties->minimumSignificantDigits = minSig;
+ fields->properties->maximumSignificantDigits = maxSig;
+ touchNoError();
}
-void DecimalFormat::getEffectiveCurrency(UChar* result, UErrorCode& ec) const {
- if (fImpl->fSymbols == NULL) {
- ec = U_MEMORY_ALLOCATION_ERROR;
+void DecimalFormat::setCurrency(const char16_t* theCurrency, UErrorCode& ec) {
+ CurrencyUnit currencyUnit(theCurrency, ec);
+ if (U_FAILURE(ec)) { return; }
+ if (!fields->properties->currency.isNull() && fields->properties->currency.getNoError() == currencyUnit) {
return;
}
- ec = U_ZERO_ERROR;
- const UChar* c = getCurrency();
- if (*c == 0) {
- const UnicodeString &intl =
- fImpl->getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol);
- c = intl.getBuffer(); // ok for intl to go out of scope
- }
- u_strncpy(result, c, 3);
- result[3] = 0;
+ NumberFormat::setCurrency(theCurrency, ec); // to set field for compatibility
+ fields->properties->currency = currencyUnit;
+ // TODO: Set values in fields->symbols, too?
+ touchNoError();
}
-Hashtable*
-DecimalFormat::initHashForAffixPattern(UErrorCode& status) {
- if ( U_FAILURE(status) ) {
- return NULL;
- }
- Hashtable* hTable;
- if ( (hTable = new Hashtable(TRUE, status)) == NULL ) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
- if ( U_FAILURE(status) ) {
- delete hTable;
- return NULL;
- }
- hTable->setValueComparator(decimfmtAffixPatternValueComparator);
- return hTable;
+void DecimalFormat::setCurrency(const char16_t* theCurrency) {
+ ErrorCode localStatus;
+ setCurrency(theCurrency, localStatus);
}
-void
-DecimalFormat::deleteHashForAffixPattern()
-{
- if ( fAffixPatternsForCurrency == NULL ) {
+void DecimalFormat::setCurrencyUsage(UCurrencyUsage newUsage, UErrorCode* ec) {
+ if (U_FAILURE(*ec)) {
return;
}
- int32_t pos = UHASH_FIRST;
- const UHashElement* element = NULL;
- while ( (element = fAffixPatternsForCurrency->nextElement(pos)) != NULL ) {
- const UHashTok valueTok = element->value;
- const AffixPatternsForCurrency* value = (AffixPatternsForCurrency*)valueTok.pointer;
- delete value;
+ if (!fields->properties->currencyUsage.isNull() && newUsage == fields->properties->currencyUsage.getNoError()) {
+ return;
}
- delete fAffixPatternsForCurrency;
- fAffixPatternsForCurrency = NULL;
+ fields->properties->currencyUsage = newUsage;
+ touch(*ec);
}
-
-void
-DecimalFormat::copyHashForAffixPattern(const Hashtable* source,
- Hashtable* target,
- UErrorCode& status) {
- if ( U_FAILURE(status) ) {
- return;
- }
- int32_t pos = UHASH_FIRST;
- const UHashElement* element = NULL;
- if ( source ) {
- while ( (element = source->nextElement(pos)) != NULL ) {
- const UHashTok keyTok = element->key;
- const UnicodeString* key = (UnicodeString*)keyTok.pointer;
- const UHashTok valueTok = element->value;
- const AffixPatternsForCurrency* value = (AffixPatternsForCurrency*)valueTok.pointer;
- AffixPatternsForCurrency* copy = new AffixPatternsForCurrency(
- value->negPrefixPatternForCurrency,
- value->negSuffixPatternForCurrency,
- value->posPrefixPatternForCurrency,
- value->posSuffixPatternForCurrency,
- value->patternType);
- target->put(UnicodeString(*key), copy, status);
- if ( U_FAILURE(status) ) {
- return;
- }
- }
+UCurrencyUsage DecimalFormat::getCurrencyUsage() const {
+ // CurrencyUsage is not exported, so we have to get it from the input property bag.
+ // TODO: Should we export CurrencyUsage instead?
+ if (fields->properties->currencyUsage.isNull()) {
+ return UCURR_USAGE_STANDARD;
}
+ return fields->properties->currencyUsage.getNoError();
}
void
-DecimalFormat::setGroupingUsed(UBool newValue) {
- NumberFormat::setGroupingUsed(newValue);
- fImpl->updateGrouping();
+DecimalFormat::formatToDecimalQuantity(double number, DecimalQuantity& output, UErrorCode& status) const {
+ fields->formatter->formatDouble(number, status).getDecimalQuantity(output, status);
}
-void
-DecimalFormat::setParseIntegerOnly(UBool newValue) {
- NumberFormat::setParseIntegerOnly(newValue);
+void DecimalFormat::formatToDecimalQuantity(const Formattable& number, DecimalQuantity& output,
+ UErrorCode& status) const {
+ UFormattedNumberData obj;
+ number.populateDecimalQuantity(obj.quantity, status);
+ fields->formatter->formatImpl(&obj, status);
+ output = std::move(obj.quantity);
}
-void
-DecimalFormat::setContext(UDisplayContext value, UErrorCode& status) {
- NumberFormat::setContext(value, status);
+const number::LocalizedNumberFormatter& DecimalFormat::toNumberFormatter() const {
+ return *fields->formatter;
}
-DecimalFormat& DecimalFormat::setAttribute( UNumberFormatAttribute attr,
- int32_t newValue,
- UErrorCode &status) {
- if(U_FAILURE(status)) return *this;
-
- switch(attr) {
- case UNUM_LENIENT_PARSE:
- setLenient(newValue!=0);
- break;
-
- case UNUM_PARSE_INT_ONLY:
- setParseIntegerOnly(newValue!=0);
- break;
-
- case UNUM_GROUPING_USED:
- setGroupingUsed(newValue!=0);
- break;
-
- case UNUM_DECIMAL_ALWAYS_SHOWN:
- setDecimalSeparatorAlwaysShown(newValue!=0);
- break;
-
- case UNUM_MAX_INTEGER_DIGITS:
- setMaximumIntegerDigits(newValue);
- break;
-
- case UNUM_MIN_INTEGER_DIGITS:
- setMinimumIntegerDigits(newValue);
- break;
-
- case UNUM_INTEGER_DIGITS:
- setMinimumIntegerDigits(newValue);
- setMaximumIntegerDigits(newValue);
- break;
-
- case UNUM_MAX_FRACTION_DIGITS:
- setMaximumFractionDigits(newValue);
- break;
-
- case UNUM_MIN_FRACTION_DIGITS:
- setMinimumFractionDigits(newValue);
- break;
-
- case UNUM_FRACTION_DIGITS:
- setMinimumFractionDigits(newValue);
- setMaximumFractionDigits(newValue);
- break;
-
- case UNUM_SIGNIFICANT_DIGITS_USED:
- setSignificantDigitsUsed(newValue!=0);
- break;
-
- case UNUM_MAX_SIGNIFICANT_DIGITS:
- setMaximumSignificantDigits(newValue);
- break;
-
- case UNUM_MIN_SIGNIFICANT_DIGITS:
- setMinimumSignificantDigits(newValue);
- break;
-
- case UNUM_MULTIPLIER:
- setMultiplier(newValue);
- break;
-
- case UNUM_GROUPING_SIZE:
- setGroupingSize(newValue);
- break;
-
- case UNUM_ROUNDING_MODE:
- setRoundingMode((DecimalFormat::ERoundingMode)newValue);
- break;
-
- case UNUM_FORMAT_WIDTH:
- setFormatWidth(newValue);
- break;
-
- case UNUM_PADDING_POSITION:
- /** The position at which padding will take place. */
- setPadPosition((DecimalFormat::EPadPosition)newValue);
- break;
-
- case UNUM_SECONDARY_GROUPING_SIZE:
- setSecondaryGroupingSize(newValue);
- break;
-
-#if UCONFIG_HAVE_PARSEALLINPUT
- case UNUM_PARSE_ALL_INPUT:
- setParseAllInput((UNumberFormatAttributeValue)newValue);
- break;
-#endif
+/** Rebuilds the formatter object from the property bag. */
+void DecimalFormat::touch(UErrorCode& status) {
+ if (fields->exportedProperties == nullptr) {
+ // fields->exportedProperties is null only when the formatter is not ready yet.
+ // The only time when this happens is during legacy deserialization.
+ return;
+ }
- /* These are stored in fBoolFlags */
- case UNUM_PARSE_NO_EXPONENT:
- case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
- case UNUM_PARSE_DECIMAL_MARK_REQUIRED:
- if(!fBoolFlags.isValidValue(newValue)) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- } else {
- if (attr == UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS) {
- fImpl->setFailIfMoreThanMaxDigits((UBool) newValue);
- }
- fBoolFlags.set(attr, newValue);
- }
- break;
+ // In C++, fields->symbols is the source of truth for the locale.
+ Locale locale = fields->symbols->getLocale();
- case UNUM_SCALE:
- fImpl->setScale(newValue);
- break;
+ // Note: The formatter is relatively cheap to create, and we need it to populate fields->exportedProperties,
+ // so automatically compute it here. The parser is a bit more expensive and is not needed until the
+ // parse method is called, so defer that until needed.
+ // TODO: Only update the pieces that changed instead of re-computing the whole formatter?
+ fields->formatter.adoptInstead(
+ new LocalizedNumberFormatter(
+ NumberPropertyMapper::create(
+ *fields->properties, *fields->symbols, fields->warehouse, *fields->exportedProperties, status).locale(
+ locale)));
- case UNUM_CURRENCY_USAGE:
- setCurrencyUsage((UCurrencyUsage)newValue, &status);
- break;
+ // Do this after fields->exportedProperties are set up
+ setupFastFormat();
- case UNUM_MINIMUM_GROUPING_DIGITS:
- setMinimumGroupingDigits(newValue);
- break;
+ // Delete the parsers if they were made previously
+ delete fields->atomicParser.exchange(nullptr);
+ delete fields->atomicCurrencyParser.exchange(nullptr);
- default:
- status = U_UNSUPPORTED_ERROR;
- break;
- }
- return *this;
+ // In order for the getters to work, we need to populate some fields in NumberFormat.
+ NumberFormat::setCurrency(fields->exportedProperties->currency.get(status).getISOCurrency(), status);
+ NumberFormat::setMaximumIntegerDigits(fields->exportedProperties->maximumIntegerDigits);
+ NumberFormat::setMinimumIntegerDigits(fields->exportedProperties->minimumIntegerDigits);
+ NumberFormat::setMaximumFractionDigits(fields->exportedProperties->maximumFractionDigits);
+ NumberFormat::setMinimumFractionDigits(fields->exportedProperties->minimumFractionDigits);
+ // fImpl->properties, not fields->exportedProperties, since this information comes from the pattern:
+ NumberFormat::setGroupingUsed(fields->properties->groupingUsed);
}
-int32_t DecimalFormat::getAttribute( UNumberFormatAttribute attr,
- UErrorCode &status ) const {
- if(U_FAILURE(status)) return -1;
- switch(attr) {
- case UNUM_LENIENT_PARSE:
- return isLenient();
-
- case UNUM_PARSE_INT_ONLY:
- return isParseIntegerOnly();
-
- case UNUM_GROUPING_USED:
- return isGroupingUsed();
-
- case UNUM_DECIMAL_ALWAYS_SHOWN:
- return isDecimalSeparatorAlwaysShown();
+void DecimalFormat::touchNoError() {
+ UErrorCode localStatus = U_ZERO_ERROR;
+ touch(localStatus);
+}
- case UNUM_MAX_INTEGER_DIGITS:
- return getMaximumIntegerDigits();
+void DecimalFormat::setPropertiesFromPattern(const UnicodeString& pattern, int32_t ignoreRounding,
+ UErrorCode& status) {
+ if (U_SUCCESS(status)) {
+ // Cast workaround to get around putting the enum in the public header file
+ auto actualIgnoreRounding = static_cast(ignoreRounding);
+ PatternParser::parseToExistingProperties(pattern, *fields->properties, actualIgnoreRounding, status);
+ }
+}
- case UNUM_MIN_INTEGER_DIGITS:
- return getMinimumIntegerDigits();
+const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& status) const {
+ if (U_FAILURE(status)) { return nullptr; }
- case UNUM_INTEGER_DIGITS:
- // TBD: what should this return?
- return getMinimumIntegerDigits();
+ // First try to get the pre-computed parser
+ auto* ptr = fields->atomicParser.load();
+ if (ptr != nullptr) {
+ return ptr;
+ }
- case UNUM_MAX_FRACTION_DIGITS:
- return getMaximumFractionDigits();
+ // Try computing the parser on our own
+ auto* temp = NumberParserImpl::createParserFromProperties(*fields->properties, *fields->symbols, false, status);
+ if (temp == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ // although we may still dereference, call sites should be guarded
+ }
- case UNUM_MIN_FRACTION_DIGITS:
- return getMinimumFractionDigits();
+ // Note: ptr starts as nullptr; during compare_exchange, it is set to what is actually stored in the
+ // atomic if another thread beat us to computing the parser object.
+ auto* nonConstThis = const_cast(this);
+ if (!nonConstThis->fields->atomicParser.compare_exchange_strong(ptr, temp)) {
+ // Another thread beat us to computing the parser
+ delete temp;
+ return ptr;
+ } else {
+ // Our copy of the parser got stored in the atomic
+ return temp;
+ }
+}
- case UNUM_FRACTION_DIGITS:
- // TBD: what should this return?
- return getMinimumFractionDigits();
+const numparse::impl::NumberParserImpl* DecimalFormat::getCurrencyParser(UErrorCode& status) const {
+ if (U_FAILURE(status)) { return nullptr; }
- case UNUM_SIGNIFICANT_DIGITS_USED:
- return areSignificantDigitsUsed();
+ // First try to get the pre-computed parser
+ auto* ptr = fields->atomicCurrencyParser.load();
+ if (ptr != nullptr) {
+ return ptr;
+ }
- case UNUM_MAX_SIGNIFICANT_DIGITS:
- return getMaximumSignificantDigits();
+ // Try computing the parser on our own
+ auto* temp = NumberParserImpl::createParserFromProperties(*fields->properties, *fields->symbols, true, status);
+ if (temp == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ // although we may still dereference, call sites should be guarded
+ }
- case UNUM_MIN_SIGNIFICANT_DIGITS:
- return getMinimumSignificantDigits();
+ // Note: ptr starts as nullptr; during compare_exchange, it is set to what is actually stored in the
+ // atomic if another thread beat us to computing the parser object.
+ auto* nonConstThis = const_cast(this);
+ if (!nonConstThis->fields->atomicCurrencyParser.compare_exchange_strong(ptr, temp)) {
+ // Another thread beat us to computing the parser
+ delete temp;
+ return ptr;
+ } else {
+ // Our copy of the parser got stored in the atomic
+ return temp;
+ }
+}
- case UNUM_MULTIPLIER:
- return getMultiplier();
+void
+DecimalFormat::fieldPositionHelper(const number::FormattedNumber& formatted, FieldPosition& fieldPosition,
+ int32_t offset, UErrorCode& status) {
+ // always return first occurrence:
+ fieldPosition.setBeginIndex(0);
+ fieldPosition.setEndIndex(0);
+ bool found = formatted.nextFieldPosition(fieldPosition, status);
+ if (found && offset != 0) {
+ FieldPositionOnlyHandler fpoh(fieldPosition);
+ fpoh.shiftLast(offset);
+ }
+}
- case UNUM_GROUPING_SIZE:
- return getGroupingSize();
+void
+DecimalFormat::fieldPositionIteratorHelper(const number::FormattedNumber& formatted, FieldPositionIterator* fpi,
+ int32_t offset, UErrorCode& status) {
+ if (fpi != nullptr) {
+ FieldPositionIteratorHandler fpih(fpi, status);
+ fpih.setShift(offset);
+ formatted.getAllFieldPositionsImpl(fpih, status);
+ }
+}
- case UNUM_ROUNDING_MODE:
- return getRoundingMode();
+// To debug fast-format, change void(x) to printf(x)
+#define trace(x) void(x)
- case UNUM_FORMAT_WIDTH:
- return getFormatWidth();
+void DecimalFormat::setupFastFormat() {
+ // Check the majority of properties:
+ if (!fields->properties->equalsDefaultExceptFastFormat()) {
+ trace("no fast format: equality\n");
+ fields->canUseFastFormat = false;
+ return;
+ }
- case UNUM_PADDING_POSITION:
- return getPadPosition();
+ // Now check the remaining properties.
+ // Nontrivial affixes:
+ UBool trivialPP = fields->properties->positivePrefixPattern.isEmpty();
+ UBool trivialPS = fields->properties->positiveSuffixPattern.isEmpty();
+ UBool trivialNP = fields->properties->negativePrefixPattern.isBogus() || (
+ fields->properties->negativePrefixPattern.length() == 1 &&
+ fields->properties->negativePrefixPattern.charAt(0) == u'-');
+ UBool trivialNS = fields->properties->negativeSuffixPattern.isEmpty();
+ if (!trivialPP || !trivialPS || !trivialNP || !trivialNS) {
+ trace("no fast format: affixes\n");
+ fields->canUseFastFormat = false;
+ return;
+ }
- case UNUM_SECONDARY_GROUPING_SIZE:
- return getSecondaryGroupingSize();
+ // Grouping (secondary grouping is forbidden in equalsDefaultExceptFastFormat):
+ bool groupingUsed = fields->properties->groupingUsed;
+ int32_t groupingSize = fields->properties->groupingSize;
+ bool unusualGroupingSize = groupingSize > 0 && groupingSize != 3;
+ const UnicodeString& groupingString = fields->symbols->getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
+ if (groupingUsed && (unusualGroupingSize || groupingString.length() != 1)) {
+ trace("no fast format: grouping\n");
+ fields->canUseFastFormat = false;
+ return;
+ }
- /* These are stored in fBoolFlags */
- case UNUM_PARSE_NO_EXPONENT:
- case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
- case UNUM_PARSE_DECIMAL_MARK_REQUIRED:
- return fBoolFlags.get(attr);
+ // Integer length:
+ int32_t minInt = fields->exportedProperties->minimumIntegerDigits;
+ int32_t maxInt = fields->exportedProperties->maximumIntegerDigits;
+ // Fastpath supports up to only 10 digits (length of INT32_MIN)
+ if (minInt > 10) {
+ trace("no fast format: integer\n");
+ fields->canUseFastFormat = false;
+ return;
+ }
- case UNUM_SCALE:
- return fImpl->fScale;
+ // Fraction length (no fraction part allowed in fast path):
+ int32_t minFrac = fields->exportedProperties->minimumFractionDigits;
+ if (minFrac > 0) {
+ trace("no fast format: fraction\n");
+ fields->canUseFastFormat = false;
+ return;
+ }
- case UNUM_CURRENCY_USAGE:
- return fImpl->getCurrencyUsage();
+ // Other symbols:
+ const UnicodeString& minusSignString = fields->symbols->getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
+ UChar32 codePointZero = fields->symbols->getCodePointZero();
+ if (minusSignString.length() != 1 || U16_LENGTH(codePointZero) != 1) {
+ trace("no fast format: symbols\n");
+ fields->canUseFastFormat = false;
+ return;
+ }
- case UNUM_MINIMUM_GROUPING_DIGITS:
- return getMinimumGroupingDigits();
+ // Good to go!
+ trace("can use fast format!\n");
+ fields->canUseFastFormat = true;
+ fields->fastData.cpZero = static_cast(codePointZero);
+ fields->fastData.cpGroupingSeparator = groupingUsed && groupingSize == 3 ? groupingString.charAt(0) : 0;
+ fields->fastData.cpMinusSign = minusSignString.charAt(0);
+ fields->fastData.minInt = (minInt < 0 || minInt > 127) ? 0 : static_cast(minInt);
+ fields->fastData.maxInt = (maxInt < 0 || maxInt > 127) ? 127 : static_cast(maxInt);
+}
- default:
- status = U_UNSUPPORTED_ERROR;
- break;
- }
+bool DecimalFormat::fastFormatDouble(double input, UnicodeString& output) const {
+ if (!fields->canUseFastFormat) {
+ return false;
+ }
+ if (std::isnan(input)
+ || std::trunc(input) != input
+ || input <= INT32_MIN
+ || input > INT32_MAX) {
+ return false;
+ }
+ doFastFormatInt32(static_cast(input), std::signbit(input), output);
+ return true;
+}
- return -1; /* undefined */
+bool DecimalFormat::fastFormatInt64(int64_t input, UnicodeString& output) const {
+ if (!fields->canUseFastFormat) {
+ return false;
+ }
+ if (input <= INT32_MIN || input > INT32_MAX) {
+ return false;
+ }
+ doFastFormatInt32(static_cast(input), input < 0, output);
+ return true;
}
-#if UCONFIG_HAVE_PARSEALLINPUT
-void DecimalFormat::setParseAllInput(UNumberFormatAttributeValue value) {
- fParseAllInput = value;
+void DecimalFormat::doFastFormatInt32(int32_t input, bool isNegative, UnicodeString& output) const {
+ U_ASSERT(fields->canUseFastFormat);
+ if (isNegative) {
+ output.append(fields->fastData.cpMinusSign);
+ U_ASSERT(input != INT32_MIN); // handled by callers
+ input = -input;
+ }
+ // Cap at int32_t to make the buffer small and operations fast.
+ // Longest string: "2,147,483,648" (13 chars in length)
+ static constexpr int32_t localCapacity = 13;
+ char16_t localBuffer[localCapacity];
+ char16_t* ptr = localBuffer + localCapacity;
+ int8_t group = 0;
+ for (int8_t i = 0; i < fields->fastData.maxInt && (input != 0 || i < fields->fastData.minInt); i++) {
+ if (group++ == 3 && fields->fastData.cpGroupingSeparator != 0) {
+ *(--ptr) = fields->fastData.cpGroupingSeparator;
+ group = 1;
+ }
+ std::div_t res = std::div(input, 10);
+ *(--ptr) = static_cast(fields->fastData.cpZero + res.rem);
+ input = res.quot;
+ }
+ int32_t len = localCapacity - static_cast(ptr - localBuffer);
+ output.append(ptr, len);
}
-#endif
-U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */
-
-//eof
diff --git a/deps/icu-small/source/i18n/decimfmtimpl.cpp b/deps/icu-small/source/i18n/decimfmtimpl.cpp
deleted file mode 100644
index ef44eab0101453..00000000000000
--- a/deps/icu-small/source/i18n/decimfmtimpl.cpp
+++ /dev/null
@@ -1,1596 +0,0 @@
-// © 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 name: decimfmtimpl.cpp
- */
-
-#include "unicode/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include
-#include "unicode/numfmt.h"
-#include "unicode/plurrule.h"
-#include "unicode/ustring.h"
-#include "decimalformatpattern.h"
-#include "decimalformatpatternimpl.h"
-#include "decimfmtimpl.h"
-#include "fphdlimp.h"
-#include "plurrule_impl.h"
-#include "valueformatter.h"
-#include "visibledigits.h"
-
-U_NAMESPACE_BEGIN
-
-static const int32_t kMaxScientificIntegerDigits = 8;
-
-static const int32_t kFormattingPosPrefix = (1 << 0);
-static const int32_t kFormattingNegPrefix = (1 << 1);
-static const int32_t kFormattingPosSuffix = (1 << 2);
-static const int32_t kFormattingNegSuffix = (1 << 3);
-static const int32_t kFormattingSymbols = (1 << 4);
-static const int32_t kFormattingCurrency = (1 << 5);
-static const int32_t kFormattingUsesCurrency = (1 << 6);
-static const int32_t kFormattingPluralRules = (1 << 7);
-static const int32_t kFormattingAffixParser = (1 << 8);
-static const int32_t kFormattingCurrencyAffixInfo = (1 << 9);
-static const int32_t kFormattingAll = (1 << 10) - 1;
-static const int32_t kFormattingAffixes =
- kFormattingPosPrefix | kFormattingPosSuffix |
- kFormattingNegPrefix | kFormattingNegSuffix;
-static const int32_t kFormattingAffixParserWithCurrency =
- kFormattingAffixParser | kFormattingCurrencyAffixInfo;
-
-DecimalFormatImpl::DecimalFormatImpl(
- NumberFormat *super,
- const Locale &locale,
- const UnicodeString &pattern,
- UErrorCode &status)
- : fSuper(super),
- fScale(0),
- fRoundingMode(DecimalFormat::kRoundHalfEven),
- fSymbols(NULL),
- fCurrencyUsage(UCURR_USAGE_STANDARD),
- fRules(NULL),
- fMonetary(FALSE) {
- if (U_FAILURE(status)) {
- return;
- }
- fSymbols = new DecimalFormatSymbols(
- locale, status);
- if (fSymbols == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- UParseError parseError;
- applyPattern(pattern, FALSE, parseError, status);
- updateAll(status);
-}
-
-DecimalFormatImpl::DecimalFormatImpl(
- NumberFormat *super,
- const UnicodeString &pattern,
- DecimalFormatSymbols *symbolsToAdopt,
- UParseError &parseError,
- UErrorCode &status)
- : fSuper(super),
- fScale(0),
- fRoundingMode(DecimalFormat::kRoundHalfEven),
- fSymbols(symbolsToAdopt),
- fCurrencyUsage(UCURR_USAGE_STANDARD),
- fRules(NULL),
- fMonetary(FALSE) {
- applyPattern(pattern, FALSE, parseError, status);
- updateAll(status);
-}
-
-DecimalFormatImpl::DecimalFormatImpl(
- NumberFormat *super, const DecimalFormatImpl &other, UErrorCode &status) :
- fSuper(super),
- fMultiplier(other.fMultiplier),
- fScale(other.fScale),
- fRoundingMode(other.fRoundingMode),
- fMinSigDigits(other.fMinSigDigits),
- fMaxSigDigits(other.fMaxSigDigits),
- fUseScientific(other.fUseScientific),
- fUseSigDigits(other.fUseSigDigits),
- fGrouping(other.fGrouping),
- fPositivePrefixPattern(other.fPositivePrefixPattern),
- fNegativePrefixPattern(other.fNegativePrefixPattern),
- fPositiveSuffixPattern(other.fPositiveSuffixPattern),
- fNegativeSuffixPattern(other.fNegativeSuffixPattern),
- fSymbols(other.fSymbols),
- fCurrencyUsage(other.fCurrencyUsage),
- fRules(NULL),
- fMonetary(other.fMonetary),
- fAffixParser(other.fAffixParser),
- fCurrencyAffixInfo(other.fCurrencyAffixInfo),
- fEffPrecision(other.fEffPrecision),
- fEffGrouping(other.fEffGrouping),
- fOptions(other.fOptions),
- fFormatter(other.fFormatter),
- fAffixes(other.fAffixes) {
- fSymbols = new DecimalFormatSymbols(*fSymbols);
- if (fSymbols == NULL && U_SUCCESS(status)) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
- if (other.fRules != NULL) {
- fRules = new PluralRules(*other.fRules);
- if (fRules == NULL && U_SUCCESS(status)) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
- }
-}
-
-
-DecimalFormatImpl &
-DecimalFormatImpl::assign(const DecimalFormatImpl &other, UErrorCode &status) {
- if (U_FAILURE(status) || this == &other) {
- return (*this);
- }
- UObject::operator=(other);
- fMultiplier = other.fMultiplier;
- fScale = other.fScale;
- fRoundingMode = other.fRoundingMode;
- fMinSigDigits = other.fMinSigDigits;
- fMaxSigDigits = other.fMaxSigDigits;
- fUseScientific = other.fUseScientific;
- fUseSigDigits = other.fUseSigDigits;
- fGrouping = other.fGrouping;
- fPositivePrefixPattern = other.fPositivePrefixPattern;
- fNegativePrefixPattern = other.fNegativePrefixPattern;
- fPositiveSuffixPattern = other.fPositiveSuffixPattern;
- fNegativeSuffixPattern = other.fNegativeSuffixPattern;
- fCurrencyUsage = other.fCurrencyUsage;
- fMonetary = other.fMonetary;
- fAffixParser = other.fAffixParser;
- fCurrencyAffixInfo = other.fCurrencyAffixInfo;
- fEffPrecision = other.fEffPrecision;
- fEffGrouping = other.fEffGrouping;
- fOptions = other.fOptions;
- fFormatter = other.fFormatter;
- fAffixes = other.fAffixes;
- *fSymbols = *other.fSymbols;
- if (fRules != NULL && other.fRules != NULL) {
- *fRules = *other.fRules;
- } else {
- delete fRules;
- fRules = other.fRules;
- if (fRules != NULL) {
- fRules = new PluralRules(*fRules);
- if (fRules == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return *this;
- }
- }
- }
- return *this;
-}
-
-UBool
-DecimalFormatImpl::operator==(const DecimalFormatImpl &other) const {
- if (this == &other) {
- return TRUE;
- }
- return (fMultiplier == other.fMultiplier)
- && (fScale == other.fScale)
- && (fRoundingMode == other.fRoundingMode)
- && (fMinSigDigits == other.fMinSigDigits)
- && (fMaxSigDigits == other.fMaxSigDigits)
- && (fUseScientific == other.fUseScientific)
- && (fUseSigDigits == other.fUseSigDigits)
- && fGrouping.equals(other.fGrouping)
- && fPositivePrefixPattern.equals(other.fPositivePrefixPattern)
- && fNegativePrefixPattern.equals(other.fNegativePrefixPattern)
- && fPositiveSuffixPattern.equals(other.fPositiveSuffixPattern)
- && fNegativeSuffixPattern.equals(other.fNegativeSuffixPattern)
- && fCurrencyUsage == other.fCurrencyUsage
- && fAffixParser.equals(other.fAffixParser)
- && fCurrencyAffixInfo.equals(other.fCurrencyAffixInfo)
- && fEffPrecision.equals(other.fEffPrecision)
- && fEffGrouping.equals(other.fEffGrouping)
- && fOptions.equals(other.fOptions)
- && fFormatter.equals(other.fFormatter)
- && fAffixes.equals(other.fAffixes)
- && (*fSymbols == *other.fSymbols)
- && ((fRules == other.fRules) || (
- (fRules != NULL) && (other.fRules != NULL)
- && (*fRules == *other.fRules)))
- && (fMonetary == other.fMonetary);
-}
-
-DecimalFormatImpl::~DecimalFormatImpl() {
- delete fSymbols;
- delete fRules;
-}
-
-ValueFormatter &
-DecimalFormatImpl::prepareValueFormatter(ValueFormatter &vf) const {
- if (fUseScientific) {
- vf.prepareScientificFormatting(
- fFormatter, fEffPrecision, fOptions);
- return vf;
- }
- vf.prepareFixedDecimalFormatting(
- fFormatter, fEffGrouping, fEffPrecision.fMantissa, fOptions.fMantissa);
- return vf;
-}
-
-int32_t
-DecimalFormatImpl::getPatternScale() const {
- UBool usesPercent = fPositivePrefixPattern.usesPercent() ||
- fPositiveSuffixPattern.usesPercent() ||
- fNegativePrefixPattern.usesPercent() ||
- fNegativeSuffixPattern.usesPercent();
- if (usesPercent) {
- return 2;
- }
- UBool usesPermill = fPositivePrefixPattern.usesPermill() ||
- fPositiveSuffixPattern.usesPermill() ||
- fNegativePrefixPattern.usesPermill() ||
- fNegativeSuffixPattern.usesPermill();
- if (usesPermill) {
- return 3;
- }
- return 0;
-}
-
-void
-DecimalFormatImpl::setMultiplierScale(int32_t scale) {
- if (scale == 0) {
- // Needed to preserve equality. fMultiplier == 0 means
- // multiplier is 1.
- fMultiplier.set((int32_t)0);
- } else {
- fMultiplier.set((int32_t)1);
- fMultiplier.shiftDecimalRight(scale);
- }
-}
-
-UnicodeString &
-DecimalFormatImpl::format(
- int32_t number,
- UnicodeString &appendTo,
- FieldPosition &pos,
- UErrorCode &status) const {
- FieldPositionOnlyHandler handler(pos);
- return formatInt32(number, appendTo, handler, status);
-}
-
-UnicodeString &
-DecimalFormatImpl::format(
- int32_t number,
- UnicodeString &appendTo,
- FieldPositionIterator *posIter,
- UErrorCode &status) const {
- FieldPositionIteratorHandler handler(posIter, status);
- return formatInt32(number, appendTo, handler, status);
-}
-
-template
-UBool DecimalFormatImpl::maybeFormatWithDigitList(
- T number,
- UnicodeString &appendTo,
- FieldPositionHandler &handler,
- UErrorCode &status) const {
- if (!fMultiplier.isZero()) {
- DigitList digits;
- digits.set(number);
- digits.mult(fMultiplier, status);
- digits.shiftDecimalRight(fScale);
- formatAdjustedDigitList(digits, appendTo, handler, status);
- return TRUE;
- }
- if (fScale != 0) {
- DigitList digits;
- digits.set(number);
- digits.shiftDecimalRight(fScale);
- formatAdjustedDigitList(digits, appendTo, handler, status);
- return TRUE;
- }
- return FALSE;
-}
-
-template
-UBool DecimalFormatImpl::maybeInitVisibleDigitsFromDigitList(
- T number,
- VisibleDigitsWithExponent &visibleDigits,
- UErrorCode &status) const {
- if (!fMultiplier.isZero()) {
- DigitList digits;
- digits.set(number);
- digits.mult(fMultiplier, status);
- digits.shiftDecimalRight(fScale);
- initVisibleDigitsFromAdjusted(digits, visibleDigits, status);
- return TRUE;
- }
- if (fScale != 0) {
- DigitList digits;
- digits.set(number);
- digits.shiftDecimalRight(fScale);
- initVisibleDigitsFromAdjusted(digits, visibleDigits, status);
- return TRUE;
- }
- return FALSE;
-}
-
-UnicodeString &
-DecimalFormatImpl::formatInt32(
- int32_t number,
- UnicodeString &appendTo,
- FieldPositionHandler &handler,
- UErrorCode &status) const {
- if (maybeFormatWithDigitList(number, appendTo, handler, status)) {
- return appendTo;
- }
- ValueFormatter vf;
- return fAffixes.formatInt32(
- number,
- prepareValueFormatter(vf),
- handler,
- fRules,
- appendTo,
- status);
-}
-
-UnicodeString &
-DecimalFormatImpl::formatInt64(
- int64_t number,
- UnicodeString &appendTo,
- FieldPositionHandler &handler,
- UErrorCode &status) const {
- if (number >= INT32_MIN && number <= INT32_MAX) {
- return formatInt32((int32_t) number, appendTo, handler, status);
- }
- VisibleDigitsWithExponent digits;
- initVisibleDigitsWithExponent(number, digits, status);
- return formatVisibleDigitsWithExponent(
- digits, appendTo, handler, status);
-}
-
-UnicodeString &
-DecimalFormatImpl::formatDouble(
- double number,
- UnicodeString &appendTo,
- FieldPositionHandler &handler,
- UErrorCode &status) const {
- VisibleDigitsWithExponent digits;
- initVisibleDigitsWithExponent(number, digits, status);
- return formatVisibleDigitsWithExponent(
- digits, appendTo, handler, status);
-}
-
-UnicodeString &
-DecimalFormatImpl::format(
- double number,
- UnicodeString &appendTo,
- FieldPosition &pos,
- UErrorCode &status) const {
- FieldPositionOnlyHandler handler(pos);
- return formatDouble(number, appendTo, handler, status);
-}
-
-UnicodeString &
-DecimalFormatImpl::format(
- const DigitList &number,
- UnicodeString &appendTo,
- FieldPosition &pos,
- UErrorCode &status) const {
- DigitList dl(number);
- FieldPositionOnlyHandler handler(pos);
- return formatDigitList(dl, appendTo, handler, status);
-}
-
-UnicodeString &
-DecimalFormatImpl::format(
- int64_t number,
- UnicodeString &appendTo,
- FieldPosition &pos,
- UErrorCode &status) const {
- FieldPositionOnlyHandler handler(pos);
- return formatInt64(number, appendTo, handler, status);
-}
-
-UnicodeString &
-DecimalFormatImpl::format(
- int64_t number,
- UnicodeString &appendTo,
- FieldPositionIterator *posIter,
- UErrorCode &status) const {
- FieldPositionIteratorHandler handler(posIter, status);
- return formatInt64(number, appendTo, handler, status);
-}
-
-UnicodeString &
-DecimalFormatImpl::format(
- double number,
- UnicodeString &appendTo,
- FieldPositionIterator *posIter,
- UErrorCode &status) const {
- FieldPositionIteratorHandler handler(posIter, status);
- return formatDouble(number, appendTo, handler, status);
-}
-
-UnicodeString &
-DecimalFormatImpl::format(
- const DigitList &number,
- UnicodeString &appendTo,
- FieldPositionIterator *posIter,
- UErrorCode &status) const {
- DigitList dl(number);
- FieldPositionIteratorHandler handler(posIter, status);
- return formatDigitList(dl, appendTo, handler, status);
-}
-
-UnicodeString &
-DecimalFormatImpl::format(
- StringPiece number,
- UnicodeString &appendTo,
- FieldPositionIterator *posIter,
- UErrorCode &status) const {
- DigitList dl;
- dl.set(number, status);
- FieldPositionIteratorHandler handler(posIter, status);
- return formatDigitList(dl, appendTo, handler, status);
-}
-
-UnicodeString &
-DecimalFormatImpl::format(
- const VisibleDigitsWithExponent &digits,
- UnicodeString &appendTo,
- FieldPosition &pos,
- UErrorCode &status) const {
- FieldPositionOnlyHandler handler(pos);
- return formatVisibleDigitsWithExponent(
- digits, appendTo, handler, status);
-}
-
-UnicodeString &
-DecimalFormatImpl::format(
- const VisibleDigitsWithExponent &digits,
- UnicodeString &appendTo,
- FieldPositionIterator *posIter,
- UErrorCode &status) const {
- FieldPositionIteratorHandler handler(posIter, status);
- return formatVisibleDigitsWithExponent(
- digits, appendTo, handler, status);
-}
-
-DigitList &
-DecimalFormatImpl::adjustDigitList(
- DigitList &number, UErrorCode &status) const {
- number.setRoundingMode(fRoundingMode);
- if (!fMultiplier.isZero()) {
- number.mult(fMultiplier, status);
- }
- if (fScale != 0) {
- number.shiftDecimalRight(fScale);
- }
- number.reduce();
- return number;
-}
-
-UnicodeString &
-DecimalFormatImpl::formatDigitList(
- DigitList &number,
- UnicodeString &appendTo,
- FieldPositionHandler &handler,
- UErrorCode &status) const {
- VisibleDigitsWithExponent digits;
- initVisibleDigitsWithExponent(number, digits, status);
- return formatVisibleDigitsWithExponent(
- digits, appendTo, handler, status);
-}
-
-UnicodeString &
-DecimalFormatImpl::formatAdjustedDigitList(
- DigitList &number,
- UnicodeString &appendTo,
- FieldPositionHandler &handler,
- UErrorCode &status) const {
- ValueFormatter vf;
- return fAffixes.format(
- number,
- prepareValueFormatter(vf),
- handler,
- fRules,
- appendTo,
- status);
-}
-
-UnicodeString &
-DecimalFormatImpl::formatVisibleDigitsWithExponent(
- const VisibleDigitsWithExponent &digits,
- UnicodeString &appendTo,
- FieldPositionHandler &handler,
- UErrorCode &status) const {
- ValueFormatter vf;
- return fAffixes.format(
- digits,
- prepareValueFormatter(vf),
- handler,
- fRules,
- appendTo,
- status);
-}
-
-static FixedDecimal &initFixedDecimal(
- const VisibleDigits &digits, FixedDecimal &result) {
- result.source = 0.0;
- result.isNegative = digits.isNegative();
- result._isNaN = digits.isNaN();
- result._isInfinite = digits.isInfinite();
- digits.getFixedDecimal(
- result.source, result.intValue, result.decimalDigits,
- result.decimalDigitsWithoutTrailingZeros,
- result.visibleDecimalDigitCount, result.hasIntegerValue);
- return result;
-}
-
-FixedDecimal &
-DecimalFormatImpl::getFixedDecimal(double number, FixedDecimal &result, UErrorCode &status) const {
- if (U_FAILURE(status)) {
- return result;
- }
- VisibleDigits digits;
- fEffPrecision.fMantissa.initVisibleDigits(number, digits, status);
- return initFixedDecimal(digits, result);
-}
-
-FixedDecimal &
-DecimalFormatImpl::getFixedDecimal(
- DigitList &number, FixedDecimal &result, UErrorCode &status) const {
- if (U_FAILURE(status)) {
- return result;
- }
- VisibleDigits digits;
- fEffPrecision.fMantissa.initVisibleDigits(number, digits, status);
- return initFixedDecimal(digits, result);
-}
-
-VisibleDigitsWithExponent &
-DecimalFormatImpl::initVisibleDigitsWithExponent(
- int64_t number,
- VisibleDigitsWithExponent &digits,
- UErrorCode &status) const {
- if (maybeInitVisibleDigitsFromDigitList(
- number, digits, status)) {
- return digits;
- }
- if (fUseScientific) {
- fEffPrecision.initVisibleDigitsWithExponent(
- number, digits, status);
- } else {
- fEffPrecision.fMantissa.initVisibleDigitsWithExponent(
- number, digits, status);
- }
- return digits;
-}
-
-VisibleDigitsWithExponent &
-DecimalFormatImpl::initVisibleDigitsWithExponent(
- double number,
- VisibleDigitsWithExponent &digits,
- UErrorCode &status) const {
- if (maybeInitVisibleDigitsFromDigitList(
- number, digits, status)) {
- return digits;
- }
- if (fUseScientific) {
- fEffPrecision.initVisibleDigitsWithExponent(
- number, digits, status);
- } else {
- fEffPrecision.fMantissa.initVisibleDigitsWithExponent(
- number, digits, status);
- }
- return digits;
-}
-
-VisibleDigitsWithExponent &
-DecimalFormatImpl::initVisibleDigitsWithExponent(
- DigitList &number,
- VisibleDigitsWithExponent &digits,
- UErrorCode &status) const {
- adjustDigitList(number, status);
- return initVisibleDigitsFromAdjusted(number, digits, status);
-}
-
-VisibleDigitsWithExponent &
-DecimalFormatImpl::initVisibleDigitsFromAdjusted(
- DigitList &number,
- VisibleDigitsWithExponent &digits,
- UErrorCode &status) const {
- if (fUseScientific) {
- fEffPrecision.initVisibleDigitsWithExponent(
- number, digits, status);
- } else {
- fEffPrecision.fMantissa.initVisibleDigitsWithExponent(
- number, digits, status);
- }
- return digits;
-}
-
-DigitList &
-DecimalFormatImpl::round(
- DigitList &number, UErrorCode &status) const {
- if (number.isNaN() || number.isInfinite()) {
- return number;
- }
- adjustDigitList(number, status);
- ValueFormatter vf;
- prepareValueFormatter(vf);
- return vf.round(number, status);
-}
-
-void
-DecimalFormatImpl::setMinimumSignificantDigits(int32_t newValue) {
- fMinSigDigits = newValue;
- fUseSigDigits = TRUE; // ticket 9936
- updatePrecision();
-}
-
-void
-DecimalFormatImpl::setMaximumSignificantDigits(int32_t newValue) {
- fMaxSigDigits = newValue;
- fUseSigDigits = TRUE; // ticket 9936
- updatePrecision();
-}
-
-void
-DecimalFormatImpl::setMinMaxSignificantDigits(int32_t min, int32_t max) {
- fMinSigDigits = min;
- fMaxSigDigits = max;
- fUseSigDigits = TRUE; // ticket 9936
- updatePrecision();
-}
-
-void
-DecimalFormatImpl::setScientificNotation(UBool newValue) {
- fUseScientific = newValue;
- updatePrecision();
-}
-
-void
-DecimalFormatImpl::setSignificantDigitsUsed(UBool newValue) {
- fUseSigDigits = newValue;
- updatePrecision();
-}
-
-void
-DecimalFormatImpl::setGroupingSize(int32_t newValue) {
- fGrouping.fGrouping = newValue;
- updateGrouping();
-}
-
-void
-DecimalFormatImpl::setSecondaryGroupingSize(int32_t newValue) {
- fGrouping.fGrouping2 = newValue;
- updateGrouping();
-}
-
-void
-DecimalFormatImpl::setMinimumGroupingDigits(int32_t newValue) {
- fGrouping.fMinGrouping = newValue;
- updateGrouping();
-}
-
-void
-DecimalFormatImpl::setCurrencyUsage(
- UCurrencyUsage currencyUsage, UErrorCode &status) {
- fCurrencyUsage = currencyUsage;
- updateFormatting(kFormattingCurrency, status);
-}
-
-void
-DecimalFormatImpl::setRoundingIncrement(double d) {
- if (d > 0.0) {
- fEffPrecision.fMantissa.fRoundingIncrement.set(d);
- } else {
- fEffPrecision.fMantissa.fRoundingIncrement.set(0.0);
- }
-}
-
-double
-DecimalFormatImpl::getRoundingIncrement() const {
- return fEffPrecision.fMantissa.fRoundingIncrement.getDouble();
-}
-
-int32_t
-DecimalFormatImpl::getMultiplier() const {
- if (fMultiplier.isZero()) {
- return 1;
- }
- return (int32_t) fMultiplier.getDouble();
-}
-
-void
-DecimalFormatImpl::setMultiplier(int32_t m) {
- if (m == 0 || m == 1) {
- fMultiplier.set((int32_t)0);
- } else {
- fMultiplier.set(m);
- }
-}
-
-void
-DecimalFormatImpl::setPositivePrefix(const UnicodeString &str) {
- fPositivePrefixPattern.remove();
- fPositivePrefixPattern.addLiteral(str.getBuffer(), 0, str.length());
- UErrorCode status = U_ZERO_ERROR;
- updateFormatting(kFormattingPosPrefix, status);
-}
-
-void
-DecimalFormatImpl::setPositiveSuffix(const UnicodeString &str) {
- fPositiveSuffixPattern.remove();
- fPositiveSuffixPattern.addLiteral(str.getBuffer(), 0, str.length());
- UErrorCode status = U_ZERO_ERROR;
- updateFormatting(kFormattingPosSuffix, status);
-}
-
-void
-DecimalFormatImpl::setNegativePrefix(const UnicodeString &str) {
- fNegativePrefixPattern.remove();
- fNegativePrefixPattern.addLiteral(str.getBuffer(), 0, str.length());
- UErrorCode status = U_ZERO_ERROR;
- updateFormatting(kFormattingNegPrefix, status);
-}
-
-void
-DecimalFormatImpl::setNegativeSuffix(const UnicodeString &str) {
- fNegativeSuffixPattern.remove();
- fNegativeSuffixPattern.addLiteral(str.getBuffer(), 0, str.length());
- UErrorCode status = U_ZERO_ERROR;
- updateFormatting(kFormattingNegSuffix, status);
-}
-
-UnicodeString &
-DecimalFormatImpl::getPositivePrefix(UnicodeString &result) const {
- result = fAffixes.fPositivePrefix.getOtherVariant().toString();
- return result;
-}
-
-UnicodeString &
-DecimalFormatImpl::getPositiveSuffix(UnicodeString &result) const {
- result = fAffixes.fPositiveSuffix.getOtherVariant().toString();
- return result;
-}
-
-UnicodeString &
-DecimalFormatImpl::getNegativePrefix(UnicodeString &result) const {
- result = fAffixes.fNegativePrefix.getOtherVariant().toString();
- return result;
-}
-
-UnicodeString &
-DecimalFormatImpl::getNegativeSuffix(UnicodeString &result) const {
- result = fAffixes.fNegativeSuffix.getOtherVariant().toString();
- return result;
-}
-
-void
-DecimalFormatImpl::adoptDecimalFormatSymbols(DecimalFormatSymbols *symbolsToAdopt) {
- if (symbolsToAdopt == NULL) {
- return;
- }
- delete fSymbols;
- fSymbols = symbolsToAdopt;
- UErrorCode status = U_ZERO_ERROR;
- updateFormatting(kFormattingSymbols, status);
-}
-
-void
-DecimalFormatImpl::applyPatternFavorCurrencyPrecision(
- const UnicodeString &pattern, UErrorCode &status) {
- UParseError perror;
- applyPattern(pattern, FALSE, perror, status);
- updateForApplyPatternFavorCurrencyPrecision(status);
-}
-
-void
-DecimalFormatImpl::applyPattern(
- const UnicodeString &pattern, UErrorCode &status) {
- UParseError perror;
- applyPattern(pattern, FALSE, perror, status);
- updateForApplyPattern(status);
-}
-
-void
-DecimalFormatImpl::applyPattern(
- const UnicodeString &pattern,
- UParseError &perror, UErrorCode &status) {
- applyPattern(pattern, FALSE, perror, status);
- updateForApplyPattern(status);
-}
-
-void
-DecimalFormatImpl::applyLocalizedPattern(
- const UnicodeString &pattern, UErrorCode &status) {
- UParseError perror;
- applyPattern(pattern, TRUE, perror, status);
- updateForApplyPattern(status);
-}
-
-void
-DecimalFormatImpl::applyLocalizedPattern(
- const UnicodeString &pattern,
- UParseError &perror, UErrorCode &status) {
- applyPattern(pattern, TRUE, perror, status);
- updateForApplyPattern(status);
-}
-
-void
-DecimalFormatImpl::applyPattern(
- const UnicodeString &pattern,
- UBool localized, UParseError &perror, UErrorCode &status) {
- if (U_FAILURE(status)) {
- return;
- }
- DecimalFormatPatternParser patternParser;
- if (localized) {
- patternParser.useSymbols(*fSymbols);
- }
- DecimalFormatPattern out;
- patternParser.applyPatternWithoutExpandAffix(
- pattern, out, perror, status);
- if (U_FAILURE(status)) {
- return;
- }
- fUseScientific = out.fUseExponentialNotation;
- fUseSigDigits = out.fUseSignificantDigits;
- fSuper->NumberFormat::setMinimumIntegerDigits(out.fMinimumIntegerDigits);
- fSuper->NumberFormat::setMaximumIntegerDigits(out.fMaximumIntegerDigits);
- fSuper->NumberFormat::setMinimumFractionDigits(out.fMinimumFractionDigits);
- fSuper->NumberFormat::setMaximumFractionDigits(out.fMaximumFractionDigits);
- fMinSigDigits = out.fMinimumSignificantDigits;
- fMaxSigDigits = out.fMaximumSignificantDigits;
- fEffPrecision.fMinExponentDigits = out.fMinExponentDigits;
- fOptions.fExponent.fAlwaysShowSign = out.fExponentSignAlwaysShown;
- fSuper->NumberFormat::setGroupingUsed(out.fGroupingUsed);
- fGrouping.fGrouping = out.fGroupingSize;
- fGrouping.fGrouping2 = out.fGroupingSize2;
- fOptions.fMantissa.fAlwaysShowDecimal = out.fDecimalSeparatorAlwaysShown;
- if (out.fRoundingIncrementUsed) {
- fEffPrecision.fMantissa.fRoundingIncrement = out.fRoundingIncrement;
- } else {
- fEffPrecision.fMantissa.fRoundingIncrement.clear();
- }
- fAffixes.fPadChar = out.fPad;
- fNegativePrefixPattern = out.fNegPrefixAffix;
- fNegativeSuffixPattern = out.fNegSuffixAffix;
- fPositivePrefixPattern = out.fPosPrefixAffix;
- fPositiveSuffixPattern = out.fPosSuffixAffix;
-
- // Work around. Pattern parsing code and DecimalFormat code don't agree
- // on the definition of field width, so we have to translate from
- // pattern field width to decimal format field width here.
- fAffixes.fWidth = out.fFormatWidth == 0 ? 0 :
- out.fFormatWidth + fPositivePrefixPattern.countChar32()
- + fPositiveSuffixPattern.countChar32();
- switch (out.fPadPosition) {
- case DecimalFormatPattern::kPadBeforePrefix:
- fAffixes.fPadPosition = DigitAffixesAndPadding::kPadBeforePrefix;
- break;
- case DecimalFormatPattern::kPadAfterPrefix:
- fAffixes.fPadPosition = DigitAffixesAndPadding::kPadAfterPrefix;
- break;
- case DecimalFormatPattern::kPadBeforeSuffix:
- fAffixes.fPadPosition = DigitAffixesAndPadding::kPadBeforeSuffix;
- break;
- case DecimalFormatPattern::kPadAfterSuffix:
- fAffixes.fPadPosition = DigitAffixesAndPadding::kPadAfterSuffix;
- break;
- default:
- break;
- }
-}
-
-void
-DecimalFormatImpl::updatePrecision() {
- if (fUseScientific) {
- updatePrecisionForScientific();
- } else {
- updatePrecisionForFixed();
- }
-}
-
-static void updatePrecisionForScientificMinMax(
- const DigitInterval &min,
- const DigitInterval &max,
- DigitInterval &resultMin,
- DigitInterval &resultMax,
- SignificantDigitInterval &resultSignificant) {
- resultMin.setIntDigitCount(0);
- resultMin.setFracDigitCount(0);
- resultSignificant.clear();
- resultMax.clear();
-
- int32_t maxIntDigitCount = max.getIntDigitCount();
- int32_t minIntDigitCount = min.getIntDigitCount();
- int32_t maxFracDigitCount = max.getFracDigitCount();
- int32_t minFracDigitCount = min.getFracDigitCount();
-
-
- // Not in spec: maxIntDigitCount > 8 assume
- // maxIntDigitCount = minIntDigitCount. Current DecimalFormat API has
- // no provision for unsetting maxIntDigitCount which would be useful for
- // scientific notation. The best we can do is assume that if
- // maxIntDigitCount is the default of 2000000000 or is "big enough" then
- // user did not intend to explicitly set it. The 8 was derived emperically
- // by extensive testing of legacy code.
- if (maxIntDigitCount > 8) {
- maxIntDigitCount = minIntDigitCount;
- }
-
- // Per the spec, exponent grouping happens if maxIntDigitCount is more
- // than 1 and more than minIntDigitCount.
- UBool bExponentGrouping = maxIntDigitCount > 1 && minIntDigitCount < maxIntDigitCount;
- if (bExponentGrouping) {
- resultMax.setIntDigitCount(maxIntDigitCount);
-
- // For exponent grouping minIntDigits is always treated as 1 even
- // if it wasn't set to 1!
- resultMin.setIntDigitCount(1);
- } else {
- // Fixed digit count left of decimal. minIntDigitCount doesn't have
- // to equal maxIntDigitCount i.e minIntDigitCount == 0 while
- // maxIntDigitCount == 1.
- int32_t fixedIntDigitCount = maxIntDigitCount;
-
- // If fixedIntDigitCount is 0 but
- // min or max fraction count is 0 too then use 1. This way we can get
- // unlimited precision for X.XXXEX
- if (fixedIntDigitCount == 0 && (minFracDigitCount == 0 || maxFracDigitCount == 0)) {
- fixedIntDigitCount = 1;
- }
- resultMax.setIntDigitCount(fixedIntDigitCount);
- resultMin.setIntDigitCount(fixedIntDigitCount);
- }
- // Spec says this is how we compute significant digits. 0 means
- // unlimited significant digits.
- int32_t maxSigDigits = minIntDigitCount + maxFracDigitCount;
- if (maxSigDigits > 0) {
- int32_t minSigDigits = minIntDigitCount + minFracDigitCount;
- resultSignificant.setMin(minSigDigits);
- resultSignificant.setMax(maxSigDigits);
- }
-}
-
-void
-DecimalFormatImpl::updatePrecisionForScientific() {
- FixedPrecision *result = &fEffPrecision.fMantissa;
- if (fUseSigDigits) {
- result->fMax.setFracDigitCount(-1);
- result->fMax.setIntDigitCount(1);
- result->fMin.setFracDigitCount(0);
- result->fMin.setIntDigitCount(1);
- result->fSignificant.clear();
- extractSigDigits(result->fSignificant);
- return;
- }
- DigitInterval max;
- DigitInterval min;
- extractMinMaxDigits(min, max);
- updatePrecisionForScientificMinMax(
- min, max,
- result->fMin, result->fMax, result->fSignificant);
-}
-
-void
-DecimalFormatImpl::updatePrecisionForFixed() {
- FixedPrecision *result = &fEffPrecision.fMantissa;
- if (!fUseSigDigits) {
- extractMinMaxDigits(result->fMin, result->fMax);
- result->fSignificant.clear();
- } else {
- extractSigDigits(result->fSignificant);
- result->fMin.setIntDigitCount(1);
- result->fMin.setFracDigitCount(0);
- result->fMax.clear();
- }
-}
-
-void
- DecimalFormatImpl::extractMinMaxDigits(
- DigitInterval &min, DigitInterval &max) const {
- min.setIntDigitCount(fSuper->getMinimumIntegerDigits());
- max.setIntDigitCount(fSuper->getMaximumIntegerDigits());
- min.setFracDigitCount(fSuper->getMinimumFractionDigits());
- max.setFracDigitCount(fSuper->getMaximumFractionDigits());
-}
-
-void
- DecimalFormatImpl::extractSigDigits(
- SignificantDigitInterval &sig) const {
- sig.setMin(fMinSigDigits < 0 ? 0 : fMinSigDigits);
- sig.setMax(fMaxSigDigits < 0 ? 0 : fMaxSigDigits);
-}
-
-void
-DecimalFormatImpl::updateGrouping() {
- if (fSuper->isGroupingUsed()) {
- fEffGrouping = fGrouping;
- } else {
- fEffGrouping.clear();
- }
-}
-
-void
-DecimalFormatImpl::updateCurrency(UErrorCode &status) {
- updateFormatting(kFormattingCurrency, TRUE, status);
-}
-
-void
-DecimalFormatImpl::updateFormatting(
- int32_t changedFormattingFields,
- UErrorCode &status) {
- updateFormatting(changedFormattingFields, TRUE, status);
-}
-
-void
-DecimalFormatImpl::updateFormatting(
- int32_t changedFormattingFields,
- UBool updatePrecisionBasedOnCurrency,
- UErrorCode &status) {
- if (U_FAILURE(status)) {
- return;
- }
- // Each function updates one field. Order matters. For instance,
- // updatePluralRules comes before updateCurrencyAffixInfo because the
- // fRules field is needed to update the fCurrencyAffixInfo field.
- updateFormattingUsesCurrency(changedFormattingFields);
- updateFormattingFixedPointFormatter(changedFormattingFields);
- updateFormattingAffixParser(changedFormattingFields);
- updateFormattingPluralRules(changedFormattingFields, status);
- updateFormattingCurrencyAffixInfo(
- changedFormattingFields,
- updatePrecisionBasedOnCurrency,
- status);
- updateFormattingLocalizedPositivePrefix(
- changedFormattingFields, status);
- updateFormattingLocalizedPositiveSuffix(
- changedFormattingFields, status);
- updateFormattingLocalizedNegativePrefix(
- changedFormattingFields, status);
- updateFormattingLocalizedNegativeSuffix(
- changedFormattingFields, status);
-}
-
-void
-DecimalFormatImpl::updateFormattingUsesCurrency(
- int32_t &changedFormattingFields) {
- if ((changedFormattingFields & kFormattingAffixes) == 0) {
- // If no affixes changed, don't need to do any work
- return;
- }
- UBool newUsesCurrency =
- fPositivePrefixPattern.usesCurrency() ||
- fPositiveSuffixPattern.usesCurrency() ||
- fNegativePrefixPattern.usesCurrency() ||
- fNegativeSuffixPattern.usesCurrency();
- if (fMonetary != newUsesCurrency) {
- fMonetary = newUsesCurrency;
- changedFormattingFields |= kFormattingUsesCurrency;
- }
-}
-
-void
-DecimalFormatImpl::updateFormattingPluralRules(
- int32_t &changedFormattingFields, UErrorCode &status) {
- if ((changedFormattingFields & (kFormattingSymbols | kFormattingUsesCurrency)) == 0) {
- // No work to do if both fSymbols and fMonetary
- // fields are unchanged
- return;
- }
- if (U_FAILURE(status)) {
- return;
- }
- PluralRules *newRules = NULL;
- if (fMonetary) {
- newRules = PluralRules::forLocale(fSymbols->getLocale(), status);
- if (U_FAILURE(status)) {
- return;
- }
- }
- // Its ok to say a field has changed when it really hasn't but not
- // the other way around. Here we assume the field changed unless it
- // was NULL before and is still NULL now
- if (fRules != newRules) {
- delete fRules;
- fRules = newRules;
- changedFormattingFields |= kFormattingPluralRules;
- }
-}
-
-void
-DecimalFormatImpl::updateFormattingCurrencyAffixInfo(
- int32_t &changedFormattingFields,
- UBool updatePrecisionBasedOnCurrency,
- UErrorCode &status) {
- if ((changedFormattingFields & (
- kFormattingSymbols | kFormattingCurrency |
- kFormattingUsesCurrency | kFormattingPluralRules)) == 0) {
- // If all these fields are unchanged, no work to do.
- return;
- }
- if (U_FAILURE(status)) {
- return;
- }
- if (!fMonetary) {
- if (fCurrencyAffixInfo.isDefault()) {
- // In this case don't have to do any work
- return;
- }
- fCurrencyAffixInfo.set(NULL, NULL, NULL, status);
- if (U_FAILURE(status)) {
- return;
- }
- changedFormattingFields |= kFormattingCurrencyAffixInfo;
- } else {
- const UChar *currency = fSuper->getCurrency();
- UChar localeCurr[4];
- if (currency[0] == 0) {
- ucurr_forLocale(fSymbols->getLocale().getName(), localeCurr, UPRV_LENGTHOF(localeCurr), &status);
- if (U_SUCCESS(status)) {
- currency = localeCurr;
- fSuper->NumberFormat::setCurrency(currency, status);
- } else {
- currency = NULL;
- status = U_ZERO_ERROR;
- }
- }
- fCurrencyAffixInfo.set(
- fSymbols->getLocale().getName(), fRules, currency, status);
- if (U_FAILURE(status)) {
- return;
- }
- UBool customCurrencySymbol = FALSE;
- // If DecimalFormatSymbols has custom currency symbol, prefer
- // that over what we just read from the resource bundles
- if (fSymbols->isCustomCurrencySymbol()) {
- fCurrencyAffixInfo.setSymbol(
- fSymbols->getConstSymbol(DecimalFormatSymbols::kCurrencySymbol));
- customCurrencySymbol = TRUE;
- }
- if (fSymbols->isCustomIntlCurrencySymbol()) {
- fCurrencyAffixInfo.setISO(
- fSymbols->getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol));
- customCurrencySymbol = TRUE;
- }
- changedFormattingFields |= kFormattingCurrencyAffixInfo;
- if (currency && !customCurrencySymbol && updatePrecisionBasedOnCurrency) {
- FixedPrecision precision;
- CurrencyAffixInfo::adjustPrecision(
- currency, fCurrencyUsage, precision, status);
- if (U_FAILURE(status)) {
- return;
- }
- fSuper->NumberFormat::setMinimumFractionDigits(
- precision.fMin.getFracDigitCount());
- fSuper->NumberFormat::setMaximumFractionDigits(
- precision.fMax.getFracDigitCount());
- updatePrecision();
- fEffPrecision.fMantissa.fRoundingIncrement =
- precision.fRoundingIncrement;
- }
-
- }
-}
-
-void
-DecimalFormatImpl::updateFormattingFixedPointFormatter(
- int32_t &changedFormattingFields) {
- if ((changedFormattingFields & (kFormattingSymbols | kFormattingUsesCurrency)) == 0) {
- // No work to do if fSymbols is unchanged
- return;
- }
- if (fMonetary) {
- fFormatter.setDecimalFormatSymbolsForMonetary(*fSymbols);
- } else {
- fFormatter.setDecimalFormatSymbols(*fSymbols);
- }
-}
-
-void
-DecimalFormatImpl::updateFormattingAffixParser(
- int32_t &changedFormattingFields) {
- if ((changedFormattingFields & kFormattingSymbols) == 0) {
- // No work to do if fSymbols is unchanged
- return;
- }
- fAffixParser.setDecimalFormatSymbols(*fSymbols);
- changedFormattingFields |= kFormattingAffixParser;
-}
-
-void
-DecimalFormatImpl::updateFormattingLocalizedPositivePrefix(
- int32_t &changedFormattingFields, UErrorCode &status) {
- if (U_FAILURE(status)) {
- return;
- }
- if ((changedFormattingFields & (
- kFormattingPosPrefix | kFormattingAffixParserWithCurrency)) == 0) {
- // No work to do
- return;
- }
- fAffixes.fPositivePrefix.remove();
- fAffixParser.parse(
- fPositivePrefixPattern,
- fCurrencyAffixInfo,
- fAffixes.fPositivePrefix,
- status);
-}
-
-void
-DecimalFormatImpl::updateFormattingLocalizedPositiveSuffix(
- int32_t &changedFormattingFields, UErrorCode &status) {
- if (U_FAILURE(status)) {
- return;
- }
- if ((changedFormattingFields & (
- kFormattingPosSuffix | kFormattingAffixParserWithCurrency)) == 0) {
- // No work to do
- return;
- }
- fAffixes.fPositiveSuffix.remove();
- fAffixParser.parse(
- fPositiveSuffixPattern,
- fCurrencyAffixInfo,
- fAffixes.fPositiveSuffix,
- status);
-}
-
-void
-DecimalFormatImpl::updateFormattingLocalizedNegativePrefix(
- int32_t &changedFormattingFields, UErrorCode &status) {
- if (U_FAILURE(status)) {
- return;
- }
- if ((changedFormattingFields & (
- kFormattingNegPrefix | kFormattingAffixParserWithCurrency)) == 0) {
- // No work to do
- return;
- }
- fAffixes.fNegativePrefix.remove();
- fAffixParser.parse(
- fNegativePrefixPattern,
- fCurrencyAffixInfo,
- fAffixes.fNegativePrefix,
- status);
-}
-
-void
-DecimalFormatImpl::updateFormattingLocalizedNegativeSuffix(
- int32_t &changedFormattingFields, UErrorCode &status) {
- if (U_FAILURE(status)) {
- return;
- }
- if ((changedFormattingFields & (
- kFormattingNegSuffix | kFormattingAffixParserWithCurrency)) == 0) {
- // No work to do
- return;
- }
- fAffixes.fNegativeSuffix.remove();
- fAffixParser.parse(
- fNegativeSuffixPattern,
- fCurrencyAffixInfo,
- fAffixes.fNegativeSuffix,
- status);
-}
-
-void
-DecimalFormatImpl::updateForApplyPatternFavorCurrencyPrecision(
- UErrorCode &status) {
- updateAll(kFormattingAll & ~kFormattingSymbols, TRUE, status);
-}
-
-void
-DecimalFormatImpl::updateForApplyPattern(UErrorCode &status) {
- updateAll(kFormattingAll & ~kFormattingSymbols, FALSE, status);
-}
-
-void
-DecimalFormatImpl::updateAll(UErrorCode &status) {
- updateAll(kFormattingAll, TRUE, status);
-}
-
-void
-DecimalFormatImpl::updateAll(
- int32_t formattingFlags,
- UBool updatePrecisionBasedOnCurrency,
- UErrorCode &status) {
- if (U_FAILURE(status)) {
- return;
- }
- updatePrecision();
- updateGrouping();
- updateFormatting(
- formattingFlags, updatePrecisionBasedOnCurrency, status);
- setMultiplierScale(getPatternScale());
-}
-
-
-static int32_t
-getMinimumLengthToDescribeGrouping(const DigitGrouping &grouping) {
- if (grouping.fGrouping <= 0) {
- return 0;
- }
- if (grouping.fGrouping2 <= 0) {
- return grouping.fGrouping + 1;
- }
- return grouping.fGrouping + grouping.fGrouping2 + 1;
-}
-
-/**
- * Given a grouping policy, calculates how many digits are needed left of
- * the decimal point to achieve a desired length left of the
- * decimal point.
- * @param grouping the grouping policy
- * @param desiredLength number of characters needed left of decimal point
- * @param minLeftDigits at least this many digits is returned
- * @param leftDigits the number of digits needed stored here
- * which is >= minLeftDigits.
- * @return true if a perfect fit or false if having leftDigits would exceed
- * desiredLength
- */
-static UBool
-getLeftDigitsForLeftLength(
- const DigitGrouping &grouping,
- int32_t desiredLength,
- int32_t minLeftDigits,
- int32_t &leftDigits) {
- leftDigits = minLeftDigits;
- int32_t lengthSoFar = leftDigits + grouping.getSeparatorCount(leftDigits);
- while (lengthSoFar < desiredLength) {
- lengthSoFar += grouping.isSeparatorAt(leftDigits + 1, leftDigits) ? 2 : 1;
- ++leftDigits;
- }
- return (lengthSoFar == desiredLength);
-}
-
-int32_t
-DecimalFormatImpl::computeExponentPatternLength() const {
- if (fUseScientific) {
- return 1 + (fOptions.fExponent.fAlwaysShowSign ? 1 : 0) + fEffPrecision.fMinExponentDigits;
- }
- return 0;
-}
-
-int32_t
-DecimalFormatImpl::countFractionDigitAndDecimalPatternLength(
- int32_t fracDigitCount) const {
- if (!fOptions.fMantissa.fAlwaysShowDecimal && fracDigitCount == 0) {
- return 0;
- }
- return fracDigitCount + 1;
-}
-
-UnicodeString&
-DecimalFormatImpl::toNumberPattern(
- UBool hasPadding, int32_t minimumLength, UnicodeString& result) const {
- // Get a grouping policy like the one in this object that does not
- // have minimum grouping since toPattern doesn't support it.
- DigitGrouping grouping(fEffGrouping);
- grouping.fMinGrouping = 0;
-
- // Only for fixed digits, these are the digits that get 0's.
- DigitInterval minInterval;
-
- // Only for fixed digits, these are the digits that get #'s.
- DigitInterval maxInterval;
-
- // Only for significant digits
- int32_t sigMin = 0; /* initialize to avoid compiler warning */
- int32_t sigMax = 0; /* initialize to avoid compiler warning */
-
- // These are all the digits to be displayed. For significant digits,
- // this interval always starts at the 1's place an extends left.
- DigitInterval fullInterval;
-
- // Digit range of rounding increment. If rounding increment is .025.
- // then roundingIncrementLowerExp = -3 and roundingIncrementUpperExp = -1
- int32_t roundingIncrementLowerExp = 0;
- int32_t roundingIncrementUpperExp = 0;
-
- if (fUseSigDigits) {
- SignificantDigitInterval sigInterval;
- extractSigDigits(sigInterval);
- sigMax = sigInterval.getMax();
- sigMin = sigInterval.getMin();
- fullInterval.setFracDigitCount(0);
- fullInterval.setIntDigitCount(sigMax);
- } else {
- extractMinMaxDigits(minInterval, maxInterval);
- if (fUseScientific) {
- if (maxInterval.getIntDigitCount() > kMaxScientificIntegerDigits) {
- maxInterval.setIntDigitCount(1);
- minInterval.shrinkToFitWithin(maxInterval);
- }
- } else if (hasPadding) {
- // Make max int digits match min int digits for now, we
- // compute necessary padding later.
- maxInterval.setIntDigitCount(minInterval.getIntDigitCount());
- } else {
- // For some reason toPattern adds at least one leading '#'
- maxInterval.setIntDigitCount(minInterval.getIntDigitCount() + 1);
- }
- if (!fEffPrecision.fMantissa.fRoundingIncrement.isZero()) {
- roundingIncrementLowerExp =
- fEffPrecision.fMantissa.fRoundingIncrement.getLowerExponent();
- roundingIncrementUpperExp =
- fEffPrecision.fMantissa.fRoundingIncrement.getUpperExponent();
- // We have to include the rounding increment in what we display
- maxInterval.expandToContainDigit(roundingIncrementLowerExp);
- maxInterval.expandToContainDigit(roundingIncrementUpperExp - 1);
- }
- fullInterval = maxInterval;
- }
- // We have to include enough digits to show grouping strategy
- int32_t minLengthToDescribeGrouping =
- getMinimumLengthToDescribeGrouping(grouping);
- if (minLengthToDescribeGrouping > 0) {
- fullInterval.expandToContainDigit(
- getMinimumLengthToDescribeGrouping(grouping) - 1);
- }
-
- // If we have a minimum length, we have to add digits to the left to
- // depict padding.
- if (hasPadding) {
- // For non scientific notation,
- // minimumLengthForMantissa = minimumLength
- int32_t minimumLengthForMantissa =
- minimumLength - computeExponentPatternLength();
- int32_t mininumLengthForMantissaIntPart =
- minimumLengthForMantissa
- - countFractionDigitAndDecimalPatternLength(
- fullInterval.getFracDigitCount());
- // Because of grouping, we may need fewer than expected digits to
- // achieve the length we need.
- int32_t digitsNeeded;
- if (getLeftDigitsForLeftLength(
- grouping,
- mininumLengthForMantissaIntPart,
- fullInterval.getIntDigitCount(),
- digitsNeeded)) {
-
- // In this case, we achieved the exact length that we want.
- fullInterval.setIntDigitCount(digitsNeeded);
- } else if (digitsNeeded > fullInterval.getIntDigitCount()) {
-
- // Having digitsNeeded digits goes over desired length which
- // means that to have desired length would mean starting on a
- // grouping sepearator e.g ,###,### so add a '#' and use one
- // less digit. This trick gives ####,### but that is the best
- // we can do.
- result.append(kPatternDigit);
- fullInterval.setIntDigitCount(digitsNeeded - 1);
- }
- }
- int32_t maxDigitPos = fullInterval.getMostSignificantExclusive();
- int32_t minDigitPos = fullInterval.getLeastSignificantInclusive();
- for (int32_t i = maxDigitPos - 1; i >= minDigitPos; --i) {
- if (!fOptions.fMantissa.fAlwaysShowDecimal && i == -1) {
- result.append(kPatternDecimalSeparator);
- }
- if (fUseSigDigits) {
- // Use digit symbol
- if (i >= sigMax || i < sigMax - sigMin) {
- result.append(kPatternDigit);
- } else {
- result.append(kPatternSignificantDigit);
- }
- } else {
- if (i < roundingIncrementUpperExp && i >= roundingIncrementLowerExp) {
- result.append((UChar)(fEffPrecision.fMantissa.fRoundingIncrement.getDigitByExponent(i) + kPatternZeroDigit));
- } else if (minInterval.contains(i)) {
- result.append(kPatternZeroDigit);
- } else {
- result.append(kPatternDigit);
- }
- }
- if (grouping.isSeparatorAt(i + 1, i)) {
- result.append(kPatternGroupingSeparator);
- }
- if (fOptions.fMantissa.fAlwaysShowDecimal && i == 0) {
- result.append(kPatternDecimalSeparator);
- }
- }
- if (fUseScientific) {
- result.append(kPatternExponent);
- if (fOptions.fExponent.fAlwaysShowSign) {
- result.append(kPatternPlus);
- }
- for (int32_t i = 0; i < 1 || i < fEffPrecision.fMinExponentDigits; ++i) {
- result.append(kPatternZeroDigit);
- }
- }
- return result;
-}
-
-UnicodeString&
-DecimalFormatImpl::toPattern(UnicodeString& result) const {
- result.remove();
- UnicodeString padSpec;
- if (fAffixes.fWidth > 0) {
- padSpec.append(kPatternPadEscape);
- padSpec.append(fAffixes.fPadChar);
- }
- if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforePrefix) {
- result.append(padSpec);
- }
- fPositivePrefixPattern.toUserString(result);
- if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterPrefix) {
- result.append(padSpec);
- }
- toNumberPattern(
- fAffixes.fWidth > 0,
- fAffixes.fWidth - fPositivePrefixPattern.countChar32() - fPositiveSuffixPattern.countChar32(),
- result);
- if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforeSuffix) {
- result.append(padSpec);
- }
- fPositiveSuffixPattern.toUserString(result);
- if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterSuffix) {
- result.append(padSpec);
- }
- AffixPattern withNegative;
- withNegative.add(AffixPattern::kNegative);
- withNegative.append(fPositivePrefixPattern);
- if (!fPositiveSuffixPattern.equals(fNegativeSuffixPattern) ||
- !withNegative.equals(fNegativePrefixPattern)) {
- result.append(kPatternSeparator);
- if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforePrefix) {
- result.append(padSpec);
- }
- fNegativePrefixPattern.toUserString(result);
- if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterPrefix) {
- result.append(padSpec);
- }
- toNumberPattern(
- fAffixes.fWidth > 0,
- fAffixes.fWidth - fNegativePrefixPattern.countChar32() - fNegativeSuffixPattern.countChar32(),
- result);
- if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadBeforeSuffix) {
- result.append(padSpec);
- }
- fNegativeSuffixPattern.toUserString(result);
- if (fAffixes.fPadPosition == DigitAffixesAndPadding::kPadAfterSuffix) {
- result.append(padSpec);
- }
- }
- return result;
-}
-
-int32_t
-DecimalFormatImpl::getOldFormatWidth() const {
- if (fAffixes.fWidth == 0) {
- return 0;
- }
- return fAffixes.fWidth - fPositiveSuffixPattern.countChar32() - fPositivePrefixPattern.countChar32();
-}
-
-const UnicodeString &
-DecimalFormatImpl::getConstSymbol(
- DecimalFormatSymbols::ENumberFormatSymbol symbol) const {
- return fSymbols->getConstSymbol(symbol);
-}
-
-UBool
-DecimalFormatImpl::isParseFastpath() const {
- AffixPattern negative;
- negative.add(AffixPattern::kNegative);
-
- return fAffixes.fWidth == 0 &&
- fPositivePrefixPattern.countChar32() == 0 &&
- fNegativePrefixPattern.equals(negative) &&
- fPositiveSuffixPattern.countChar32() == 0 &&
- fNegativeSuffixPattern.countChar32() == 0;
-}
-
-
-U_NAMESPACE_END
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/deps/icu-small/source/i18n/decimfmtimpl.h b/deps/icu-small/source/i18n/decimfmtimpl.h
deleted file mode 100644
index b4438cba9e1ea8..00000000000000
--- a/deps/icu-small/source/i18n/decimfmtimpl.h
+++ /dev/null
@@ -1,549 +0,0 @@
-// © 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 decimfmtimpl.h
-********************************************************************************
-*/
-
-#ifndef DECIMFMTIMPL_H
-#define DECIMFMTIMPL_H
-
-#include "unicode/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/decimfmt.h"
-#include "unicode/uobject.h"
-#include "affixpatternparser.h"
-#include "digitaffixesandpadding.h"
-#include "digitformatter.h"
-#include "digitgrouping.h"
-#include "precision.h"
-
-U_NAMESPACE_BEGIN
-
-class UnicodeString;
-class FieldPosition;
-class ValueFormatter;
-class FieldPositionHandler;
-class FixedDecimal;
-
-/**
- * DecimalFormatImpl is the glue code between the legacy DecimalFormat class
- * and the new decimal formatting classes. DecimalFormat still handles
- * parsing directly. However, DecimalFormat uses attributes of this class
- * for parsing when possible.
- *
- * The public API of this class closely mirrors the legacy API of the
- * legacy DecimalFormat deviating only when the legacy API does not make
- * sense. For example, although DecimalFormat has a
- * getPadCharacterString() method, DecimalFormatImpl has a getPadCharacter()
- * method because formatting uses only a single pad character for padding.
- *
- * Each legacy DecimalFormat instance heap allocates its own instance of
- * this class. Most DecimalFormat methods that deal with formatting simply
- * delegate to the DecimalFormat's DecimalFormatImpl method.
- *
- * Because DecimalFormat extends NumberFormat, Each instance of this class
- * "borrows" a pointer to the NumberFormat part of its enclosing DecimalFormat
- * instance. This way each DecimalFormatImpl instance can read or even modify
- * the NumberFormat portion of its enclosing DecimalFormat instance.
- *
- * Directed acyclic graph (DAG):
- *
- * This class can be represented as a directed acyclic graph (DAG) where each
- * vertex is an attribute, and each directed edge indicates that the value
- * of the destination attribute is calculated from the value of the source
- * attribute. Attributes with setter methods reside at the bottom of the
- * DAG. That is, no edges point to them. We call these independent attributes
- * because their values can be set independently of one another. The rest of
- * the attributes are derived attributes because their values depend on the
- * independent attributes. DecimalFormatImpl often uses the derived
- * attributes, not the independent attributes, when formatting numbers.
- *
- * The independent attributes at the bottom of the DAG correspond to the legacy
- * attributes of DecimalFormat while the attributes at the top of the DAG
- * correspond to the attributes of the new code. The edges of the DAG
- * correspond to the code that handles the complex interaction among all the
- * legacy attributes of the DecimalFormat API.
- *
- * We use a DAG for three reasons.
- *
- * First, the DAG preserves backward compatibility. Clients of the legacy
- * DecimalFormat expect existing getters and setters of each attribute to be
- * consistent. That means if a client sets a particular attribute to a new
- * value, the attribute should retain that value until the client sets it to
- * a new value. The DAG allows these attributes to remain consistent even
- * though the new code may not use them when formatting.
- *
- * Second, the DAG obviates the need to recalculate derived attributes with
- * each format. Instead, the DAG "remembers" the values of all derived
- * attributes. Only setting an independent attribute requires a recalculation.
- * Moreover, setting an independent attribute recalculates only the affected
- * dependent attributes rather than all dependent attributes.
- *
- * Third, the DAG abstracts away the complex interaction among the legacy
- * attributes of the DecimalFormat API.
- *
- * Only the independent attributes of the DAG have setters and getters.
- * Derived attributes have no setters (and often no getters either).
- *
- * Copy and assign:
- *
- * For copy and assign, DecimalFormatImpl copies and assigns every attribute
- * regardless of whether or not it is independent. We do this for simplicity.
- *
- * Implementation of the DAG:
- *
- * The DAG consists of three smaller DAGs:
- * 1. Grouping attributes
- * 2. Precision attributes
- * 3. Formatting attributes.
- *
- * The first two DAGs are simple in that setting any independent attribute
- * in the DAG recalculates all the dependent attributes in that DAG.
- * The updateGrouping() and updatePrecision() perform the respective
- * recalculations.
- *
- * Because some of the derived formatting attributes are expensive to
- * calculate, the formatting attributes DAG is more complex. The
- * updateFormatting() method is composed of many updateFormattingXXX()
- * methods, each of which recalculates a single derived attribute. The
- * updateFormatting() method accepts a bitfield of recently changed
- * attributes and passes this bitfield by reference to each of the
- * updateFormattingXXX() methods. Each updateFormattingXXX() method checks
- * the bitfield to see if any of the attributes it uses to compute the XXX
- * attribute changed. If none of them changed, it exists immediately. However,
- * if at least one of them changed, it recalculates the XXX attribute and
- * sets the corresponding bit in the bitfield. In this way, each
- * updateFormattingXXX() method encodes the directed edges in the formatting
- * DAG that point to the attribute its calculating.
- *
- * Maintenance of the updateFormatting() method.
- *
- * Use care when changing the updateFormatting() method.
- * The updateFormatting() method must call each updateFormattingXXX() in the
- * same partial order that the formatting DAG prescribes. That is, the
- * attributes near the bottom of the DAG must be calculated before attributes
- * further up. As we mentioned in the prvious paragraph, the directed edges of
- * the formatting DAG are encoded within each updateFormattingXXX() method.
- * Finally, adding new attributes may involve adding to the bitmap that the
- * updateFormatting() method uses. The top most attributes in the DAG,
- * those that do not point to any attributes but only have attributes
- * pointing to it, need not have a slot in the bitmap.
- *
- * Keep in mind that most of the code that makes the legacy DecimalFormat API
- * work the way it always has before can be found in these various updateXXX()
- * methods. For example the updatePrecisionForScientific() method
- * handles the complex interactions amoung the various precision attributes
- * when formatting in scientific notation. Changing the way attributes
- * interract, often means changing one of these updateXXX() methods.
- *
- * Conclusion:
- *
- * The DecimFmtImpl class is the glue code between the legacy and new
- * number formatting code. It uses a direct acyclic graph (DAG) to
- * maintain backward compatibility, to make the code efficient, and to
- * abstract away the complex interraction among legacy attributs.
- */
-
-
-class DecimalFormatImpl : public UObject {
-public:
-
-DecimalFormatImpl(
- NumberFormat *super,
- const Locale &locale,
- const UnicodeString &pattern,
- UErrorCode &status);
-DecimalFormatImpl(
- NumberFormat *super,
- const UnicodeString &pattern,
- DecimalFormatSymbols *symbolsToAdopt,
- UParseError &parseError,
- UErrorCode &status);
-DecimalFormatImpl(
- NumberFormat *super,
- const DecimalFormatImpl &other,
- UErrorCode &status);
-DecimalFormatImpl &assign(
- const DecimalFormatImpl &other, UErrorCode &status);
-virtual ~DecimalFormatImpl();
-void adoptDecimalFormatSymbols(DecimalFormatSymbols *symbolsToAdopt);
-const DecimalFormatSymbols &getDecimalFormatSymbols() const {
- return *fSymbols;
-}
-UnicodeString &format(
- int32_t number,
- UnicodeString &appendTo,
- FieldPosition &pos,
- UErrorCode &status) const;
-UnicodeString &format(
- int32_t number,
- UnicodeString &appendTo,
- FieldPositionIterator *posIter,
- UErrorCode &status) const;
-UnicodeString &format(
- int64_t number,
- UnicodeString &appendTo,
- FieldPosition &pos,
- UErrorCode &status) const;
-UnicodeString &format(
- double number,
- UnicodeString &appendTo,
- FieldPosition &pos,
- UErrorCode &status) const;
-UnicodeString &format(
- const DigitList &number,
- UnicodeString &appendTo,
- FieldPosition &pos,
- UErrorCode &status) const;
-UnicodeString &format(
- int64_t number,
- UnicodeString &appendTo,
- FieldPositionIterator *posIter,
- UErrorCode &status) const;
-UnicodeString &format(
- double number,
- UnicodeString &appendTo,
- FieldPositionIterator *posIter,
- UErrorCode &status) const;
-UnicodeString &format(
- const DigitList &number,
- UnicodeString &appendTo,
- FieldPositionIterator *posIter,
- UErrorCode &status) const;
-UnicodeString &format(
- StringPiece number,
- UnicodeString &appendTo,
- FieldPositionIterator *posIter,
- UErrorCode &status) const;
-UnicodeString &format(
- const VisibleDigitsWithExponent &digits,
- UnicodeString &appendTo,
- FieldPosition &pos,
- UErrorCode &status) const;
-UnicodeString &format(
- const VisibleDigitsWithExponent &digits,
- UnicodeString &appendTo,
- FieldPositionIterator *posIter,
- UErrorCode &status) const;
-
-UBool operator==(const DecimalFormatImpl &) const;
-
-UBool operator!=(const DecimalFormatImpl &other) const {
- return !(*this == other);
-}
-
-void setRoundingMode(DecimalFormat::ERoundingMode mode) {
- fRoundingMode = mode;
- fEffPrecision.fMantissa.fExactOnly = (fRoundingMode == DecimalFormat::kRoundUnnecessary);
- fEffPrecision.fMantissa.fRoundingMode = mode;
-}
-DecimalFormat::ERoundingMode getRoundingMode() const {
- return fRoundingMode;
-}
-void setFailIfMoreThanMaxDigits(UBool b) {
- fEffPrecision.fMantissa.fFailIfOverMax = b;
-}
-UBool isFailIfMoreThanMaxDigits() const { return fEffPrecision.fMantissa.fFailIfOverMax; }
-void setMinimumSignificantDigits(int32_t newValue);
-void setMaximumSignificantDigits(int32_t newValue);
-void setMinMaxSignificantDigits(int32_t min, int32_t max);
-void setScientificNotation(UBool newValue);
-void setSignificantDigitsUsed(UBool newValue);
-
-int32_t getMinimumSignificantDigits() const {
- return fMinSigDigits; }
-int32_t getMaximumSignificantDigits() const {
- return fMaxSigDigits; }
-UBool isScientificNotation() const { return fUseScientific; }
-UBool areSignificantDigitsUsed() const { return fUseSigDigits; }
-void setGroupingSize(int32_t newValue);
-void setSecondaryGroupingSize(int32_t newValue);
-void setMinimumGroupingDigits(int32_t newValue);
-int32_t getGroupingSize() const { return fGrouping.fGrouping; }
-int32_t getSecondaryGroupingSize() const { return fGrouping.fGrouping2; }
-int32_t getMinimumGroupingDigits() const { return fGrouping.fMinGrouping; }
-void applyPattern(const UnicodeString &pattern, UErrorCode &status);
-void applyPatternFavorCurrencyPrecision(
- const UnicodeString &pattern, UErrorCode &status);
-void applyPattern(
- const UnicodeString &pattern, UParseError &perror, UErrorCode &status);
-void applyLocalizedPattern(const UnicodeString &pattern, UErrorCode &status);
-void applyLocalizedPattern(
- const UnicodeString &pattern, UParseError &perror, UErrorCode &status);
-void setCurrencyUsage(UCurrencyUsage usage, UErrorCode &status);
-UCurrencyUsage getCurrencyUsage() const { return fCurrencyUsage; }
-void setRoundingIncrement(double d);
-double getRoundingIncrement() const;
-int32_t getMultiplier() const;
-void setMultiplier(int32_t m);
-UChar32 getPadCharacter() const { return fAffixes.fPadChar; }
-void setPadCharacter(UChar32 c) { fAffixes.fPadChar = c; }
-int32_t getFormatWidth() const { return fAffixes.fWidth; }
-void setFormatWidth(int32_t x) { fAffixes.fWidth = x; }
-DigitAffixesAndPadding::EPadPosition getPadPosition() const {
- return fAffixes.fPadPosition;
-}
-void setPadPosition(DigitAffixesAndPadding::EPadPosition x) {
- fAffixes.fPadPosition = x;
-}
-int32_t getMinimumExponentDigits() const {
- return fEffPrecision.fMinExponentDigits;
-}
-void setMinimumExponentDigits(int32_t x) {
- fEffPrecision.fMinExponentDigits = x;
-}
-UBool isExponentSignAlwaysShown() const {
- return fOptions.fExponent.fAlwaysShowSign;
-}
-void setExponentSignAlwaysShown(UBool x) {
- fOptions.fExponent.fAlwaysShowSign = x;
-}
-UBool isDecimalSeparatorAlwaysShown() const {
- return fOptions.fMantissa.fAlwaysShowDecimal;
-}
-void setDecimalSeparatorAlwaysShown(UBool x) {
- fOptions.fMantissa.fAlwaysShowDecimal = x;
-}
-UnicodeString &getPositivePrefix(UnicodeString &result) const;
-UnicodeString &getPositiveSuffix(UnicodeString &result) const;
-UnicodeString &getNegativePrefix(UnicodeString &result) const;
-UnicodeString &getNegativeSuffix(UnicodeString &result) const;
-void setPositivePrefix(const UnicodeString &str);
-void setPositiveSuffix(const UnicodeString &str);
-void setNegativePrefix(const UnicodeString &str);
-void setNegativeSuffix(const UnicodeString &str);
-UnicodeString &toPattern(UnicodeString& result) const;
-FixedDecimal &getFixedDecimal(double value, FixedDecimal &result, UErrorCode &status) const;
-FixedDecimal &getFixedDecimal(DigitList &number, FixedDecimal &result, UErrorCode &status) const;
-DigitList &round(DigitList &number, UErrorCode &status) const;
-
-VisibleDigitsWithExponent &
-initVisibleDigitsWithExponent(
- int64_t number,
- VisibleDigitsWithExponent &digits,
- UErrorCode &status) const;
-VisibleDigitsWithExponent &
-initVisibleDigitsWithExponent(
- double number,
- VisibleDigitsWithExponent &digits,
- UErrorCode &status) const;
-VisibleDigitsWithExponent &
-initVisibleDigitsWithExponent(
- DigitList &number,
- VisibleDigitsWithExponent &digits,
- UErrorCode &status) const;
-
-void updatePrecision();
-void updateGrouping();
-void updateCurrency(UErrorCode &status);
-
-
-private:
-// Disallow copy and assign
-DecimalFormatImpl(const DecimalFormatImpl &other);
-DecimalFormatImpl &operator=(const DecimalFormatImpl &other);
-NumberFormat *fSuper;
-DigitList fMultiplier;
-int32_t fScale;
-
-DecimalFormat::ERoundingMode fRoundingMode;
-
-// These fields include what the user can see and set.
-// When the user updates these fields, it triggers automatic updates of
-// other fields that may be invisible to user
-
-// Updating any of the following fields triggers an update to
-// fEffPrecision.fMantissa.fMin,
-// fEffPrecision.fMantissa.fMax,
-// fEffPrecision.fMantissa.fSignificant fields
-// We have this two phase update because of backward compatibility.
-// DecimalFormat has to remember all settings even if those settings are
-// invalid or disabled.
-int32_t fMinSigDigits;
-int32_t fMaxSigDigits;
-UBool fUseScientific;
-UBool fUseSigDigits;
-// In addition to these listed above, changes to min/max int digits and
-// min/max frac digits from fSuper also trigger an update.
-
-// Updating any of the following fields triggers an update to
-// fEffGrouping field Again we do it this way because original
-// grouping settings have to be retained if grouping is turned off.
-DigitGrouping fGrouping;
-// In addition to these listed above, changes to isGroupingUsed in
-// fSuper also triggers an update to fEffGrouping.
-
-// Updating any of the following fields triggers updates on the following:
-// fMonetary, fRules, fAffixParser, fCurrencyAffixInfo,
-// fFormatter, fAffixes.fPositivePrefiix, fAffixes.fPositiveSuffix,
-// fAffixes.fNegativePrefiix, fAffixes.fNegativeSuffix
-// We do this two phase update because localizing the affix patterns
-// and formatters can be expensive. Better to do it once with the setters
-// than each time within format.
-AffixPattern fPositivePrefixPattern;
-AffixPattern fNegativePrefixPattern;
-AffixPattern fPositiveSuffixPattern;
-AffixPattern fNegativeSuffixPattern;
-DecimalFormatSymbols *fSymbols;
-UCurrencyUsage fCurrencyUsage;
-// In addition to these listed above, changes to getCurrency() in
-// fSuper also triggers an update.
-
-// Optional may be NULL
-PluralRules *fRules;
-
-// These fields are totally hidden from user and are used to derive the affixes
-// in fAffixes below from the four affix patterns above.
-UBool fMonetary;
-AffixPatternParser fAffixParser;
-CurrencyAffixInfo fCurrencyAffixInfo;
-
-// The actual precision used when formatting
-ScientificPrecision fEffPrecision;
-
-// The actual grouping used when formatting
-DigitGrouping fEffGrouping;
-SciFormatterOptions fOptions; // Encapsulates fixed precision options
-DigitFormatter fFormatter;
-DigitAffixesAndPadding fAffixes;
-
-UnicodeString &formatInt32(
- int32_t number,
- UnicodeString &appendTo,
- FieldPositionHandler &handler,
- UErrorCode &status) const;
-
-UnicodeString &formatInt64(
- int64_t number,
- UnicodeString &appendTo,
- FieldPositionHandler &handler,
- UErrorCode &status) const;
-
-UnicodeString &formatDouble(
- double number,
- UnicodeString &appendTo,
- FieldPositionHandler &handler,
- UErrorCode &status) const;
-
-// Scales for precent or permille symbols
-UnicodeString &formatDigitList(
- DigitList &number,
- UnicodeString &appendTo,
- FieldPositionHandler &handler,
- UErrorCode &status) const;
-
-// Does not scale for precent or permille symbols
-UnicodeString &formatAdjustedDigitList(
- DigitList &number,
- UnicodeString &appendTo,
- FieldPositionHandler &handler,
- UErrorCode &status) const;
-
-UnicodeString &formatVisibleDigitsWithExponent(
- const VisibleDigitsWithExponent &number,
- UnicodeString &appendTo,
- FieldPositionHandler &handler,
- UErrorCode &status) const;
-
-VisibleDigitsWithExponent &
-initVisibleDigitsFromAdjusted(
- DigitList &number,
- VisibleDigitsWithExponent &digits,
- UErrorCode &status) const;
-
-template
-UBool maybeFormatWithDigitList(
- T number,
- UnicodeString &appendTo,
- FieldPositionHandler &handler,
- UErrorCode &status) const;
-
-template
-UBool maybeInitVisibleDigitsFromDigitList(
- T number,
- VisibleDigitsWithExponent &digits,
- UErrorCode &status) const;
-
-DigitList &adjustDigitList(DigitList &number, UErrorCode &status) const;
-
-void applyPattern(
- const UnicodeString &pattern,
- UBool localized, UParseError &perror, UErrorCode &status);
-
-ValueFormatter &prepareValueFormatter(ValueFormatter &vf) const;
-void setMultiplierScale(int32_t s);
-int32_t getPatternScale() const;
-void setScale(int32_t s) { fScale = s; }
-int32_t getScale() const { return fScale; }
-
-// Updates everything
-void updateAll(UErrorCode &status);
-void updateAll(
- int32_t formattingFlags,
- UBool updatePrecisionBasedOnCurrency,
- UErrorCode &status);
-
-// Updates from formatting pattern changes
-void updateForApplyPattern(UErrorCode &status);
-void updateForApplyPatternFavorCurrencyPrecision(UErrorCode &status);
-
-// Updates from changes to third group of attributes
-void updateFormatting(int32_t changedFormattingFields, UErrorCode &status);
-void updateFormatting(
- int32_t changedFormattingFields,
- UBool updatePrecisionBasedOnCurrency,
- UErrorCode &status);
-
-// Helper functions for updatePrecision
-void updatePrecisionForScientific();
-void updatePrecisionForFixed();
-void extractMinMaxDigits(DigitInterval &min, DigitInterval &max) const;
-void extractSigDigits(SignificantDigitInterval &sig) const;
-
-// Helper functions for updateFormatting
-void updateFormattingUsesCurrency(int32_t &changedFormattingFields);
-void updateFormattingPluralRules(
- int32_t &changedFormattingFields, UErrorCode &status);
-void updateFormattingAffixParser(int32_t &changedFormattingFields);
-void updateFormattingCurrencyAffixInfo(
- int32_t &changedFormattingFields,
- UBool updatePrecisionBasedOnCurrency,
- UErrorCode &status);
-void updateFormattingFixedPointFormatter(
- int32_t &changedFormattingFields);
-void updateFormattingLocalizedPositivePrefix(
- int32_t &changedFormattingFields, UErrorCode &status);
-void updateFormattingLocalizedPositiveSuffix(
- int32_t &changedFormattingFields, UErrorCode &status);
-void updateFormattingLocalizedNegativePrefix(
- int32_t &changedFormattingFields, UErrorCode &status);
-void updateFormattingLocalizedNegativeSuffix(
- int32_t &changedFormattingFields, UErrorCode &status);
-
-int32_t computeExponentPatternLength() const;
-int32_t countFractionDigitAndDecimalPatternLength(int32_t fracDigitCount) const;
-UnicodeString &toNumberPattern(
- UBool hasPadding, int32_t minimumLength, UnicodeString& result) const;
-
-int32_t getOldFormatWidth() const;
-const UnicodeString &getConstSymbol(
- DecimalFormatSymbols::ENumberFormatSymbol symbol) const;
-UBool isParseFastpath() const;
-
-friend class DecimalFormat;
-
-};
-
-
-U_NAMESPACE_END
-#endif /* #if !UCONFIG_NO_FORMATTING */
-#endif // DECIMFMTIMPL_H
-//eof
diff --git a/deps/icu-small/source/i18n/digitaffix.cpp b/deps/icu-small/source/i18n/digitaffix.cpp
deleted file mode 100644
index 396df2cf1d75eb..00000000000000
--- a/deps/icu-small/source/i18n/digitaffix.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-// © 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 name: digitaffix.cpp
- */
-
-#include "unicode/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "digitaffix.h"
-#include "fphdlimp.h"
-#include "uassert.h"
-#include "unistrappender.h"
-
-U_NAMESPACE_BEGIN
-
-DigitAffix::DigitAffix() : fAffix(), fAnnotations() {
-}
-
-DigitAffix::DigitAffix(
- const UChar *value, int32_t charCount, int32_t fieldId)
- : fAffix(value, charCount),
- fAnnotations(charCount, (UChar) fieldId, charCount) {
-}
-
-void
-DigitAffix::remove() {
- fAffix.remove();
- fAnnotations.remove();
-}
-
-void
-DigitAffix::appendUChar(UChar value, int32_t fieldId) {
- fAffix.append(value);
- fAnnotations.append((UChar) fieldId);
-}
-
-void
-DigitAffix::append(const UnicodeString &value, int32_t fieldId) {
- fAffix.append(value);
- {
- UnicodeStringAppender appender(fAnnotations);
- int32_t len = value.length();
- for (int32_t i = 0; i < len; ++i) {
- appender.append((UChar) fieldId);
- }
- }
-}
-
-void
-DigitAffix::setTo(const UnicodeString &value, int32_t fieldId) {
- fAffix = value;
- fAnnotations.remove();
- {
- UnicodeStringAppender appender(fAnnotations);
- int32_t len = value.length();
- for (int32_t i = 0; i < len; ++i) {
- appender.append((UChar) fieldId);
- }
- }
-}
-
-void
-DigitAffix::append(const UChar *value, int32_t charCount, int32_t fieldId) {
- fAffix.append(value, charCount);
- {
- UnicodeStringAppender appender(fAnnotations);
- for (int32_t i = 0; i < charCount; ++i) {
- appender.append((UChar) fieldId);
- }
- }
-}
-
-UnicodeString &
-DigitAffix::format(FieldPositionHandler &handler, UnicodeString &appendTo) const {
- int32_t len = fAffix.length();
- if (len == 0) {
- return appendTo;
- }
- if (!handler.isRecording()) {
- return appendTo.append(fAffix);
- }
- U_ASSERT(fAffix.length() == fAnnotations.length());
- int32_t appendToStart = appendTo.length();
- int32_t lastId = (int32_t) fAnnotations.charAt(0);
- int32_t lastIdStart = 0;
- for (int32_t i = 1; i < len; ++i) {
- int32_t id = (int32_t) fAnnotations.charAt(i);
- if (id != lastId) {
- if (lastId != UNUM_FIELD_COUNT) {
- handler.addAttribute(lastId, appendToStart + lastIdStart, appendToStart + i);
- }
- lastId = id;
- lastIdStart = i;
- }
- }
- if (lastId != UNUM_FIELD_COUNT) {
- handler.addAttribute(lastId, appendToStart + lastIdStart, appendToStart + len);
- }
- return appendTo.append(fAffix);
-}
-
-U_NAMESPACE_END
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/deps/icu-small/source/i18n/digitaffix.h b/deps/icu-small/source/i18n/digitaffix.h
deleted file mode 100644
index 005c36f8488d8f..00000000000000
--- a/deps/icu-small/source/i18n/digitaffix.h
+++ /dev/null
@@ -1,104 +0,0 @@
-// © 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.
-*******************************************************************************
-* digitaffix.h
-*
-* created on: 2015jan06
-* created by: Travis Keep
-*/
-
-#ifndef __DIGITAFFIX_H__
-#define __DIGITAFFIX_H__
-
-#include "unicode/uobject.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/unistr.h"
-#include "unicode/unum.h"
-#include "unicode/utypes.h"
-
-U_NAMESPACE_BEGIN
-
-class FieldPositionHandler;
-
-/**
- * A prefix or suffix of a formatted number.
- */
-class U_I18N_API DigitAffix : public UMemory {
-public:
-
- /**
- * Creates an empty DigitAffix.
- */
- DigitAffix();
-
- /**
- * Creates a DigitAffix containing given UChars where all of it has
- * a field type of fieldId.
- */
- DigitAffix(
- const UChar *value,
- int32_t charCount,
- int32_t fieldId=UNUM_FIELD_COUNT);
-
- /**
- * Makes this affix be the empty string.
- */
- void remove();
-
- /**
- * Append value to this affix. If fieldId is present, the appended
- * string is considered to be the type fieldId.
- */
- void appendUChar(UChar value, int32_t fieldId=UNUM_FIELD_COUNT);
-
- /**
- * Append value to this affix. If fieldId is present, the appended
- * string is considered to be the type fieldId.
- */
- void append(const UnicodeString &value, int32_t fieldId=UNUM_FIELD_COUNT);
-
- /**
- * Sets this affix to given string. The entire string
- * is considered to be the type fieldId.
- */
- void setTo(const UnicodeString &value, int32_t fieldId=UNUM_FIELD_COUNT);
-
- /**
- * Append value to this affix. If fieldId is present, the appended
- * string is considered to be the type fieldId.
- */
- void append(const UChar *value, int32_t charCount, int32_t fieldId=UNUM_FIELD_COUNT);
-
- /**
- * Formats this affix.
- */
- UnicodeString &format(
- FieldPositionHandler &handler, UnicodeString &appendTo) const;
- int32_t countChar32() const { return fAffix.countChar32(); }
-
- /**
- * Returns this affix as a unicode string.
- */
- const UnicodeString & toString() const { return fAffix; }
-
- /**
- * Returns TRUE if this object equals rhs.
- */
- UBool equals(const DigitAffix &rhs) const {
- return ((fAffix == rhs.fAffix) && (fAnnotations == rhs.fAnnotations));
- }
-private:
- UnicodeString fAffix;
- UnicodeString fAnnotations;
-};
-
-
-U_NAMESPACE_END
-#endif // #if !UCONFIG_NO_FORMATTING
-#endif // __DIGITAFFIX_H__
diff --git a/deps/icu-small/source/i18n/digitaffixesandpadding.cpp b/deps/icu-small/source/i18n/digitaffixesandpadding.cpp
deleted file mode 100644
index 487d9a345d3e21..00000000000000
--- a/deps/icu-small/source/i18n/digitaffixesandpadding.cpp
+++ /dev/null
@@ -1,175 +0,0 @@
-// © 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 name: digitaffixesandpadding.cpp
- */
-
-#include "unicode/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/plurrule.h"
-#include "charstr.h"
-#include "digitaffix.h"
-#include "digitaffixesandpadding.h"
-#include "digitlst.h"
-#include "uassert.h"
-#include "valueformatter.h"
-#include "visibledigits.h"
-
-U_NAMESPACE_BEGIN
-
-UBool
-DigitAffixesAndPadding::needsPluralRules() const {
- return (
- fPositivePrefix.hasMultipleVariants() ||
- fPositiveSuffix.hasMultipleVariants() ||
- fNegativePrefix.hasMultipleVariants() ||
- fNegativeSuffix.hasMultipleVariants());
-}
-
-UnicodeString &
-DigitAffixesAndPadding::formatInt32(
- int32_t value,
- const ValueFormatter &formatter,
- FieldPositionHandler &handler,
- const PluralRules *optPluralRules,
- UnicodeString &appendTo,
- UErrorCode &status) const {
- if (U_FAILURE(status)) {
- return appendTo;
- }
- if (optPluralRules != NULL || fWidth > 0 || !formatter.isFastFormattable(value)) {
- VisibleDigitsWithExponent digits;
- formatter.toVisibleDigitsWithExponent(
- (int64_t) value, digits, status);
- return format(
- digits,
- formatter,
- handler,
- optPluralRules,
- appendTo,
- status);
- }
- UBool bPositive = value >= 0;
- const DigitAffix *prefix = bPositive ? &fPositivePrefix.getOtherVariant() : &fNegativePrefix.getOtherVariant();
- const DigitAffix *suffix = bPositive ? &fPositiveSuffix.getOtherVariant() : &fNegativeSuffix.getOtherVariant();
- if (value < 0) {
- value = -value;
- }
- prefix->format(handler, appendTo);
- formatter.formatInt32(value, handler, appendTo);
- return suffix->format(handler, appendTo);
-}
-
-static UnicodeString &
-formatAffix(
- const DigitAffix *affix,
- FieldPositionHandler &handler,
- UnicodeString &appendTo) {
- if (affix) {
- affix->format(handler, appendTo);
- }
- return appendTo;
-}
-
-static int32_t
-countAffixChar32(const DigitAffix *affix) {
- if (affix) {
- return affix->countChar32();
- }
- return 0;
-}
-
-UnicodeString &
-DigitAffixesAndPadding::format(
- const VisibleDigitsWithExponent &digits,
- const ValueFormatter &formatter,
- FieldPositionHandler &handler,
- const PluralRules *optPluralRules,
- UnicodeString &appendTo,
- UErrorCode &status) const {
- if (U_FAILURE(status)) {
- return appendTo;
- }
- const DigitAffix *prefix = NULL;
- const DigitAffix *suffix = NULL;
- if (!digits.isNaN()) {
- UBool bPositive = !digits.isNegative();
- const PluralAffix *pluralPrefix = bPositive ? &fPositivePrefix : &fNegativePrefix;
- const PluralAffix *pluralSuffix = bPositive ? &fPositiveSuffix : &fNegativeSuffix;
- if (optPluralRules == NULL || digits.isInfinite()) {
- prefix = &pluralPrefix->getOtherVariant();
- suffix = &pluralSuffix->getOtherVariant();
- } else {
- UnicodeString count(optPluralRules->select(digits));
- prefix = &pluralPrefix->getByCategory(count);
- suffix = &pluralSuffix->getByCategory(count);
- }
- }
- if (fWidth <= 0) {
- formatAffix(prefix, handler, appendTo);
- formatter.format(digits, handler, appendTo);
- return formatAffix(suffix, handler, appendTo);
- }
- int32_t codePointCount = countAffixChar32(prefix) + formatter.countChar32(digits) + countAffixChar32(suffix);
- int32_t paddingCount = fWidth - codePointCount;
- switch (fPadPosition) {
- case kPadBeforePrefix:
- appendPadding(paddingCount, appendTo);
- formatAffix(prefix, handler, appendTo);
- formatter.format(digits, handler, appendTo);
- return formatAffix(suffix, handler, appendTo);
- case kPadAfterPrefix:
- formatAffix(prefix, handler, appendTo);
- appendPadding(paddingCount, appendTo);
- formatter.format(digits, handler, appendTo);
- return formatAffix(suffix, handler, appendTo);
- case kPadBeforeSuffix:
- formatAffix(prefix, handler, appendTo);
- formatter.format(digits, handler, appendTo);
- appendPadding(paddingCount, appendTo);
- return formatAffix(suffix, handler, appendTo);
- case kPadAfterSuffix:
- formatAffix(prefix, handler, appendTo);
- formatter.format(digits, handler, appendTo);
- formatAffix(suffix, handler, appendTo);
- return appendPadding(paddingCount, appendTo);
- default:
- U_ASSERT(FALSE);
- return appendTo;
- }
-}
-
-UnicodeString &
-DigitAffixesAndPadding::format(
- DigitList &value,
- const ValueFormatter &formatter,
- FieldPositionHandler &handler,
- const PluralRules *optPluralRules,
- UnicodeString &appendTo,
- UErrorCode &status) const {
- VisibleDigitsWithExponent digits;
- formatter.toVisibleDigitsWithExponent(
- value, digits, status);
- if (U_FAILURE(status)) {
- return appendTo;
- }
- return format(
- digits, formatter, handler, optPluralRules, appendTo, status);
-}
-
-UnicodeString &
-DigitAffixesAndPadding::appendPadding(int32_t paddingCount, UnicodeString &appendTo) const {
- for (int32_t i = 0; i < paddingCount; ++i) {
- appendTo.append(fPadChar);
- }
- return appendTo;
-}
-
-
-U_NAMESPACE_END
-#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/deps/icu-small/source/i18n/digitaffixesandpadding.h b/deps/icu-small/source/i18n/digitaffixesandpadding.h
deleted file mode 100644
index d570599d180e77..00000000000000
--- a/deps/icu-small/source/i18n/digitaffixesandpadding.h
+++ /dev/null
@@ -1,179 +0,0 @@
-// © 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.
-*******************************************************************************
-* digitaffixesandpadding.h
-*
-* created on: 2015jan06
-* created by: Travis Keep
-*/
-
-#ifndef __DIGITAFFIXESANDPADDING_H__
-#define __DIGITAFFIXESANDPADDING_H__
-
-#include "unicode/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/uobject.h"
-#include "pluralaffix.h"
-
-U_NAMESPACE_BEGIN
-
-class DigitList;
-class ValueFormatter;
-class UnicodeString;
-class FieldPositionHandler;
-class PluralRules;
-class VisibleDigitsWithExponent;
-
-/**
- * A formatter of numbers. This class can format any numerical value
- * except for not a number (NaN), positive infinity, and negative infinity.
- * This class manages prefixes, suffixes, and padding but delegates the
- * formatting of actual positive values to a ValueFormatter.
- */
-class U_I18N_API DigitAffixesAndPadding : public UMemory {
-public:
-
-/**
- * Equivalent to DecimalFormat EPadPosition, but redeclared here to prevent
- * depending on DecimalFormat which would cause a circular dependency.
- */
-enum EPadPosition {
- kPadBeforePrefix,
- kPadAfterPrefix,
- kPadBeforeSuffix,
- kPadAfterSuffix
-};
-
-/**
- * The positive prefix
- */
-PluralAffix fPositivePrefix;
-
-/**
- * The positive suffix
- */
-PluralAffix fPositiveSuffix;
-
-/**
- * The negative suffix
- */
-PluralAffix fNegativePrefix;
-
-/**
- * The negative suffix
- */
-PluralAffix fNegativeSuffix;
-
-/**
- * The padding position
- */
-EPadPosition fPadPosition;
-
-/**
- * The padding character.
- */
-UChar32 fPadChar;
-
-/**
- * The field width in code points. The format method inserts instances of
- * the padding character as needed in the desired padding position so that
- * the entire formatted string contains this many code points. If the
- * formatted string already exceeds this many code points, the format method
- * inserts no padding.
- */
-int32_t fWidth;
-
-/**
- * Pad position is before prefix; padding character is '*' field width is 0.
- * The affixes are all the empty string with no annotated fields with just
- * the 'other' plural variation.
- */
-DigitAffixesAndPadding()
- : fPadPosition(kPadBeforePrefix), fPadChar(0x2a), fWidth(0) { }
-
-/**
- * Returns TRUE if this object is equal to rhs.
- */
-UBool equals(const DigitAffixesAndPadding &rhs) const {
- return (fPositivePrefix.equals(rhs.fPositivePrefix) &&
- fPositiveSuffix.equals(rhs.fPositiveSuffix) &&
- fNegativePrefix.equals(rhs.fNegativePrefix) &&
- fNegativeSuffix.equals(rhs.fNegativeSuffix) &&
- fPadPosition == rhs.fPadPosition &&
- fWidth == rhs.fWidth &&
- fPadChar == rhs.fPadChar);
-}
-
-/**
- * Returns TRUE if a plural rules instance is needed to complete the
- * formatting by detecting if any of the affixes have multiple plural
- * variations.
- */
-UBool needsPluralRules() const;
-
-/**
- * Formats value and appends to appendTo.
- *
- * @param value the value to format. May be NaN or ininite.
- * @param formatter handles the details of formatting the actual value.
- * @param handler records field positions
- * @param optPluralRules the plural rules, but may be NULL if
- * needsPluralRules returns FALSE.
- * @appendTo formatted string appended here.
- * @status any error returned here.
- */
-UnicodeString &format(
- const VisibleDigitsWithExponent &value,
- const ValueFormatter &formatter,
- FieldPositionHandler &handler,
- const PluralRules *optPluralRules,
- UnicodeString &appendTo,
- UErrorCode &status) const;
-
-/**
- * For testing only.
- */
-UnicodeString &format(
- DigitList &value,
- const ValueFormatter &formatter,
- FieldPositionHandler &handler,
- const PluralRules *optPluralRules,
- UnicodeString &appendTo,
- UErrorCode &status) const;
-
-/**
- * Formats a 32-bit integer and appends to appendTo. When formatting an
- * integer, this method is preferred to plain format as it can run
- * several times faster under certain conditions.
- *
- * @param value the value to format.
- * @param formatter handles the details of formatting the actual value.
- * @param handler records field positions
- * @param optPluralRules the plural rules, but may be NULL if
- * needsPluralRules returns FALSE.
- * @appendTo formatted string appended here.
- * @status any error returned here.
- */
-UnicodeString &formatInt32(
- int32_t value,
- const ValueFormatter &formatter,
- FieldPositionHandler &handler,
- const PluralRules *optPluralRules,
- UnicodeString &appendTo,
- UErrorCode &status) const;
-
-private:
-UnicodeString &appendPadding(int32_t paddingCount, UnicodeString &appendTo) const;
-
-};
-
-
-U_NAMESPACE_END
-#endif /* #if !UCONFIG_NO_FORMATTING */
-#endif // __DIGITAFFIXANDPADDING_H__
diff --git a/deps/icu-small/source/i18n/digitformatter.cpp b/deps/icu-small/source/i18n/digitformatter.cpp
deleted file mode 100644
index 0d857f8f6873c6..00000000000000
--- a/deps/icu-small/source/i18n/digitformatter.cpp
+++ /dev/null
@@ -1,417 +0,0 @@
-// © 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 name: digitformatter.cpp
- */
-
-#include "unicode/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/dcfmtsym.h"
-#include "unicode/unum.h"
-
-#include "digitformatter.h"
-#include "digitgrouping.h"
-#include "digitinterval.h"
-#include "digitlst.h"
-#include "fphdlimp.h"
-#include "smallintformatter.h"
-#include "unistrappender.h"
-#include "visibledigits.h"
-
-U_NAMESPACE_BEGIN
-
-DigitFormatter::DigitFormatter()
- : fGroupingSeparator(",", -1, US_INV), fDecimal(".", -1, US_INV),
- fNegativeSign("-", -1, US_INV), fPositiveSign("+", -1, US_INV),
- fIsStandardDigits(TRUE), fExponent("E", -1, US_INV) {
- for (int32_t i = 0; i < 10; ++i) {
- fLocalizedDigits[i] = (UChar32) (0x30 + i);
- }
- fInfinity.setTo(UnicodeString("Inf", -1, US_INV), UNUM_INTEGER_FIELD);
- fNan.setTo(UnicodeString("Nan", -1, US_INV), UNUM_INTEGER_FIELD);
-}
-
-DigitFormatter::DigitFormatter(const DecimalFormatSymbols &symbols) {
- setDecimalFormatSymbols(symbols);
-}
-
-void
-DigitFormatter::setOtherDecimalFormatSymbols(
- const DecimalFormatSymbols &symbols) {
- fLocalizedDigits[0] = symbols.getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
- fLocalizedDigits[1] = symbols.getConstSymbol(DecimalFormatSymbols::kOneDigitSymbol).char32At(0);
- fLocalizedDigits[2] = symbols.getConstSymbol(DecimalFormatSymbols::kTwoDigitSymbol).char32At(0);
- fLocalizedDigits[3] = symbols.getConstSymbol(DecimalFormatSymbols::kThreeDigitSymbol).char32At(0);
- fLocalizedDigits[4] = symbols.getConstSymbol(DecimalFormatSymbols::kFourDigitSymbol).char32At(0);
- fLocalizedDigits[5] = symbols.getConstSymbol(DecimalFormatSymbols::kFiveDigitSymbol).char32At(0);
- fLocalizedDigits[6] = symbols.getConstSymbol(DecimalFormatSymbols::kSixDigitSymbol).char32At(0);
- fLocalizedDigits[7] = symbols.getConstSymbol(DecimalFormatSymbols::kSevenDigitSymbol).char32At(0);
- fLocalizedDigits[8] = symbols.getConstSymbol(DecimalFormatSymbols::kEightDigitSymbol).char32At(0);
- fLocalizedDigits[9] = symbols.getConstSymbol(DecimalFormatSymbols::kNineDigitSymbol).char32At(0);
- fIsStandardDigits = isStandardDigits();
- fNegativeSign = symbols.getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
- fPositiveSign = symbols.getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
- fInfinity.setTo(symbols.getConstSymbol(DecimalFormatSymbols::kInfinitySymbol), UNUM_INTEGER_FIELD);
- fNan.setTo(symbols.getConstSymbol(DecimalFormatSymbols::kNaNSymbol), UNUM_INTEGER_FIELD);
- fExponent = symbols.getConstSymbol(DecimalFormatSymbols::kExponentialSymbol);
-}
-
-void
-DigitFormatter::setDecimalFormatSymbolsForMonetary(
- const DecimalFormatSymbols &symbols) {
- setOtherDecimalFormatSymbols(symbols);
- fGroupingSeparator = symbols.getConstSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol);
- fDecimal = symbols.getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
-}
-
-void
-DigitFormatter::setDecimalFormatSymbols(
- const DecimalFormatSymbols &symbols) {
- setOtherDecimalFormatSymbols(symbols);
- fGroupingSeparator = symbols.getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
- fDecimal = symbols.getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
-}
-
-static void appendField(
- int32_t fieldId,
- const UnicodeString &value,
- FieldPositionHandler &handler,
- UnicodeString &appendTo) {
- int32_t currentLength = appendTo.length();
- appendTo.append(value);
- handler.addAttribute(
- fieldId,
- currentLength,
- appendTo.length());
-}
-
-int32_t DigitFormatter::countChar32(
- const DigitGrouping &grouping,
- const DigitInterval &interval,
- const DigitFormatterOptions &options) const {
- int32_t result = interval.length();
-
- // We always emit '0' in lieu of no digits.
- if (result == 0) {
- result = 1;
- }
- if (options.fAlwaysShowDecimal || interval.getLeastSignificantInclusive() < 0) {
- result += fDecimal.countChar32();
- }
- result += grouping.getSeparatorCount(interval.getIntDigitCount()) * fGroupingSeparator.countChar32();
- return result;
-}
-
-int32_t
-DigitFormatter::countChar32(
- const VisibleDigits &digits,
- const DigitGrouping &grouping,
- const DigitFormatterOptions &options) const {
- if (digits.isNaN()) {
- return countChar32ForNaN();
- }
- if (digits.isInfinite()) {
- return countChar32ForInfinity();
- }
- return countChar32(
- grouping,
- digits.getInterval(),
- options);
-}
-
-int32_t
-DigitFormatter::countChar32(
- const VisibleDigitsWithExponent &digits,
- const SciFormatterOptions &options) const {
- if (digits.isNaN()) {
- return countChar32ForNaN();
- }
- if (digits.isInfinite()) {
- return countChar32ForInfinity();
- }
- const VisibleDigits *exponent = digits.getExponent();
- if (exponent == NULL) {
- DigitGrouping grouping;
- return countChar32(
- grouping,
- digits.getMantissa().getInterval(),
- options.fMantissa);
- }
- return countChar32(
- *exponent, digits.getMantissa().getInterval(), options);
-}
-
-int32_t
-DigitFormatter::countChar32(
- const VisibleDigits &exponent,
- const DigitInterval &mantissaInterval,
- const SciFormatterOptions &options) const {
- DigitGrouping grouping;
- int32_t count = countChar32(
- grouping, mantissaInterval, options.fMantissa);
- count += fExponent.countChar32();
- count += countChar32ForExponent(
- exponent, options.fExponent);
- return count;
-}
-
-UnicodeString &DigitFormatter::format(
- const VisibleDigits &digits,
- const DigitGrouping &grouping,
- const DigitFormatterOptions &options,
- FieldPositionHandler &handler,
- UnicodeString &appendTo) const {
- if (digits.isNaN()) {
- return formatNaN(handler, appendTo);
- }
- if (digits.isInfinite()) {
- return formatInfinity(handler, appendTo);
- }
-
- const DigitInterval &interval = digits.getInterval();
- int32_t digitsLeftOfDecimal = interval.getMostSignificantExclusive();
- int32_t lastDigitPos = interval.getLeastSignificantInclusive();
- int32_t intBegin = appendTo.length();
- int32_t fracBegin = 0; /* initialize to avoid compiler warning */
-
- // Emit "0" instead of empty string.
- if (digitsLeftOfDecimal == 0 && lastDigitPos == 0) {
- appendTo.append(fLocalizedDigits[0]);
- handler.addAttribute(UNUM_INTEGER_FIELD, intBegin, appendTo.length());
- if (options.fAlwaysShowDecimal) {
- appendField(
- UNUM_DECIMAL_SEPARATOR_FIELD,
- fDecimal,
- handler,
- appendTo);
- }
- return appendTo;
- }
- {
- UnicodeStringAppender appender(appendTo);
- for (int32_t i = interval.getMostSignificantExclusive() - 1;
- i >= interval.getLeastSignificantInclusive(); --i) {
- if (i == -1) {
- appender.flush();
- appendField(
- UNUM_DECIMAL_SEPARATOR_FIELD,
- fDecimal,
- handler,
- appendTo);
- fracBegin = appendTo.length();
- }
- appender.append(fLocalizedDigits[digits.getDigitByExponent(i)]);
- if (grouping.isSeparatorAt(digitsLeftOfDecimal, i)) {
- appender.flush();
- appendField(
- UNUM_GROUPING_SEPARATOR_FIELD,
- fGroupingSeparator,
- handler,
- appendTo);
- }
- if (i == 0) {
- appender.flush();
- if (digitsLeftOfDecimal > 0) {
- handler.addAttribute(UNUM_INTEGER_FIELD, intBegin, appendTo.length());
- }
- }
- }
- if (options.fAlwaysShowDecimal && lastDigitPos == 0) {
- appender.flush();
- appendField(
- UNUM_DECIMAL_SEPARATOR_FIELD,
- fDecimal,
- handler,
- appendTo);
- }
- }
- // lastDigitPos is never > 0 so we are guaranteed that kIntegerField
- // is already added.
- if (lastDigitPos < 0) {
- handler.addAttribute(UNUM_FRACTION_FIELD, fracBegin, appendTo.length());
- }
- return appendTo;
-}
-
-UnicodeString &
-DigitFormatter::format(
- const VisibleDigitsWithExponent &digits,
- const SciFormatterOptions &options,
- FieldPositionHandler &handler,
- UnicodeString &appendTo) const {
- DigitGrouping grouping;
- format(
- digits.getMantissa(),
- grouping,
- options.fMantissa,
- handler,
- appendTo);
- const VisibleDigits *exponent = digits.getExponent();
- if (exponent == NULL) {
- return appendTo;
- }
- int32_t expBegin = appendTo.length();
- appendTo.append(fExponent);
- handler.addAttribute(
- UNUM_EXPONENT_SYMBOL_FIELD, expBegin, appendTo.length());
- return formatExponent(
- *exponent,
- options.fExponent,
- UNUM_EXPONENT_SIGN_FIELD,
- UNUM_EXPONENT_FIELD,
- handler,
- appendTo);
-}
-
-static int32_t formatInt(
- int32_t value, uint8_t *digits) {
- int32_t idx = 0;
- while (value > 0) {
- digits[idx++] = (uint8_t) (value % 10);
- value /= 10;
- }
- return idx;
-}
-
-UnicodeString &
-DigitFormatter::formatDigits(
- const uint8_t *digits,
- int32_t count,
- const IntDigitCountRange &range,
- int32_t intField,
- FieldPositionHandler &handler,
- UnicodeString &appendTo) const {
- int32_t i = range.pin(count) - 1;
- int32_t begin = appendTo.length();
-
- // Always emit '0' as placeholder for empty string.
- if (i == -1) {
- appendTo.append(fLocalizedDigits[0]);
- handler.addAttribute(intField, begin, appendTo.length());
- return appendTo;
- }
- {
- UnicodeStringAppender appender(appendTo);
- for (; i >= count; --i) {
- appender.append(fLocalizedDigits[0]);
- }
- for (; i >= 0; --i) {
- appender.append(fLocalizedDigits[digits[i]]);
- }
- }
- handler.addAttribute(intField, begin, appendTo.length());
- return appendTo;
-}
-
-UnicodeString &
-DigitFormatter::formatExponent(
- const VisibleDigits &digits,
- const DigitFormatterIntOptions &options,
- int32_t signField,
- int32_t intField,
- FieldPositionHandler &handler,
- UnicodeString &appendTo) const {
- UBool neg = digits.isNegative();
- if (neg || options.fAlwaysShowSign) {
- appendField(
- signField,
- neg ? fNegativeSign : fPositiveSign,
- handler,
- appendTo);
- }
- int32_t begin = appendTo.length();
- DigitGrouping grouping;
- DigitFormatterOptions expOptions;
- FieldPosition fpos(FieldPosition::DONT_CARE);
- FieldPositionOnlyHandler noHandler(fpos);
- format(
- digits,
- grouping,
- expOptions,
- noHandler,
- appendTo);
- handler.addAttribute(intField, begin, appendTo.length());
- return appendTo;
-}
-
-int32_t
-DigitFormatter::countChar32ForExponent(
- const VisibleDigits &exponent,
- const DigitFormatterIntOptions &options) const {
- int32_t result = 0;
- UBool neg = exponent.isNegative();
- if (neg || options.fAlwaysShowSign) {
- result += neg ? fNegativeSign.countChar32() : fPositiveSign.countChar32();
- }
- DigitGrouping grouping;
- DigitFormatterOptions expOptions;
- result += countChar32(grouping, exponent.getInterval(), expOptions);
- return result;
-}
-
-UnicodeString &
-DigitFormatter::formatPositiveInt32(
- int32_t positiveValue,
- const IntDigitCountRange &range,
- FieldPositionHandler &handler,
- UnicodeString &appendTo) const {
- // super fast path
- if (fIsStandardDigits && SmallIntFormatter::canFormat(positiveValue, range)) {
- int32_t begin = appendTo.length();
- SmallIntFormatter::format(positiveValue, range, appendTo);
- handler.addAttribute(UNUM_INTEGER_FIELD, begin, appendTo.length());
- return appendTo;
- }
- uint8_t digits[10];
- int32_t count = formatInt(positiveValue, digits);
- return formatDigits(
- digits,
- count,
- range,
- UNUM_INTEGER_FIELD,
- handler,
- appendTo);
-}
-
-UBool DigitFormatter::isStandardDigits() const {
- UChar32 cdigit = 0x30;
- for (int32_t i = 0; i < UPRV_LENGTHOF(fLocalizedDigits); ++i) {
- if (fLocalizedDigits[i] != cdigit) {
- return FALSE;
- }
- ++cdigit;
- }
- return TRUE;
-}
-
-UBool
-DigitFormatter::equals(const DigitFormatter &rhs) const {
- UBool result = (fGroupingSeparator == rhs.fGroupingSeparator) &&
- (fDecimal == rhs.fDecimal) &&
- (fNegativeSign == rhs.fNegativeSign) &&
- (fPositiveSign == rhs.fPositiveSign) &&
- (fInfinity.equals(rhs.fInfinity)) &&
- (fNan.equals(rhs.fNan)) &&
- (fIsStandardDigits == rhs.fIsStandardDigits) &&
- (fExponent == rhs.fExponent);
-
- if (!result) {
- return FALSE;
- }
- for (int32_t i = 0; i < UPRV_LENGTHOF(fLocalizedDigits); ++i) {
- if (fLocalizedDigits[i] != rhs.fLocalizedDigits[i]) {
- return FALSE;
- }
- }
- return TRUE;
-}
-
-
-U_NAMESPACE_END
-
-#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/deps/icu-small/source/i18n/digitformatter.h b/deps/icu-small/source/i18n/digitformatter.h
deleted file mode 100644
index 54a54c3639a629..00000000000000
--- a/deps/icu-small/source/i18n/digitformatter.h
+++ /dev/null
@@ -1,288 +0,0 @@
-// © 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.
-*******************************************************************************
-* digitformatter.h
-*
-* created on: 2015jan06
-* created by: Travis Keep
-*/
-
-#ifndef __DIGITFORMATTER_H__
-#define __DIGITFORMATTER_H__
-
-#include "unicode/uobject.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/utypes.h"
-#include "unicode/unistr.h"
-#include "digitaffix.h"
-
-U_NAMESPACE_BEGIN
-
-class DecimalFormatSymbols;
-class DigitList;
-class DigitGrouping;
-class DigitInterval;
-class UnicodeString;
-class FieldPositionHandler;
-class IntDigitCountRange;
-class VisibleDigits;
-class VisibleDigitsWithExponent;
-
-/**
- * Various options for formatting in fixed point.
- */
-class U_I18N_API DigitFormatterOptions : public UMemory {
- public:
- DigitFormatterOptions() : fAlwaysShowDecimal(FALSE) { }
-
- /**
- * Returns TRUE if this object equals rhs.
- */
- UBool equals(const DigitFormatterOptions &rhs) const {
- return (
- fAlwaysShowDecimal == rhs.fAlwaysShowDecimal);
- }
-
- /**
- * Returns TRUE if these options allow for fast formatting of
- * integers.
- */
- UBool isFastFormattable() const {
- return (fAlwaysShowDecimal == FALSE);
- }
-
- /**
- * If TRUE, show the decimal separator even when there are no fraction
- * digits. default is FALSE.
- */
- UBool fAlwaysShowDecimal;
-};
-
-/**
- * Various options for formatting an integer.
- */
-class U_I18N_API DigitFormatterIntOptions : public UMemory {
- public:
- DigitFormatterIntOptions() : fAlwaysShowSign(FALSE) { }
-
- /**
- * Returns TRUE if this object equals rhs.
- */
- UBool equals(const DigitFormatterIntOptions &rhs) const {
- return (fAlwaysShowSign == rhs.fAlwaysShowSign);
- }
-
- /**
- * If TRUE, always prefix the integer with its sign even if the number is
- * positive. Default is FALSE.
- */
- UBool fAlwaysShowSign;
-};
-
-/**
- * Options for formatting in scientific notation.
- */
-class U_I18N_API SciFormatterOptions : public UMemory {
- public:
-
- /**
- * Returns TRUE if this object equals rhs.
- */
- UBool equals(const SciFormatterOptions &rhs) const {
- return (fMantissa.equals(rhs.fMantissa) &&
- fExponent.equals(rhs.fExponent));
- }
-
- /**
- * Options for formatting the mantissa.
- */
- DigitFormatterOptions fMantissa;
-
- /**
- * Options for formatting the exponent.
- */
- DigitFormatterIntOptions fExponent;
-};
-
-
-/**
- * Does fixed point formatting.
- *
- * This class only does fixed point formatting. It does no rounding before
- * formatting.
- */
-class U_I18N_API DigitFormatter : public UMemory {
-public:
-
-/**
- * Decimal separator is period (.), Plus sign is plus (+),
- * minus sign is minus (-), grouping separator is comma (,), digits are 0-9.
- */
-DigitFormatter();
-
-/**
- * Let symbols determine the digits, decimal separator,
- * plus and mius sign, grouping separator, and possibly other settings.
- */
-DigitFormatter(const DecimalFormatSymbols &symbols);
-
-/**
- * Change what this instance uses for digits, decimal separator,
- * plus and mius sign, grouping separator, and possibly other settings
- * according to symbols.
- */
-void setDecimalFormatSymbols(const DecimalFormatSymbols &symbols);
-
-/**
- * Change what this instance uses for digits, decimal separator,
- * plus and mius sign, grouping separator, and possibly other settings
- * according to symbols in the context of monetary amounts.
- */
-void setDecimalFormatSymbolsForMonetary(const DecimalFormatSymbols &symbols);
-
-/**
- * Fixed point formatting.
- *
- * @param positiveDigits the value to format
- * Negative sign can be present, but it won't show.
- * @param grouping controls how digit grouping is done
- * @param options formatting options
- * @param handler records field positions
- * @param appendTo formatted value appended here.
- * @return appendTo
- */
-UnicodeString &format(
- const VisibleDigits &positiveDigits,
- const DigitGrouping &grouping,
- const DigitFormatterOptions &options,
- FieldPositionHandler &handler,
- UnicodeString &appendTo) const;
-
-/**
- * formats in scientifc notation.
- * @param positiveDigits the value to format.
- * Negative sign can be present, but it won't show.
- * @param options formatting options
- * @param handler records field positions.
- * @param appendTo formatted value appended here.
- */
-UnicodeString &format(
- const VisibleDigitsWithExponent &positiveDigits,
- const SciFormatterOptions &options,
- FieldPositionHandler &handler,
- UnicodeString &appendTo) const;
-
-/**
- * Fixed point formatting of integers.
- * Always performed with no grouping and no decimal point.
- *
- * @param positiveValue the value to format must be positive.
- * @param range specifies minimum and maximum number of digits.
- * @param handler records field positions
- * @param appendTo formatted value appended here.
- * @return appendTo
- */
-UnicodeString &formatPositiveInt32(
- int32_t positiveValue,
- const IntDigitCountRange &range,
- FieldPositionHandler &handler,
- UnicodeString &appendTo) const;
-
-/**
- * Counts how many code points are needed for fixed formatting.
- * If digits is negative, the negative sign is not included in the count.
- */
-int32_t countChar32(
- const VisibleDigits &digits,
- const DigitGrouping &grouping,
- const DigitFormatterOptions &options) const;
-
-/**
- * Counts how many code points are needed for scientific formatting.
- * If digits is negative, the negative sign is not included in the count.
- */
-int32_t countChar32(
- const VisibleDigitsWithExponent &digits,
- const SciFormatterOptions &options) const;
-
-/**
- * Returns TRUE if this object equals rhs.
- */
-UBool equals(const DigitFormatter &rhs) const;
-
-private:
-UChar32 fLocalizedDigits[10];
-UnicodeString fGroupingSeparator;
-UnicodeString fDecimal;
-UnicodeString fNegativeSign;
-UnicodeString fPositiveSign;
-DigitAffix fInfinity;
-DigitAffix fNan;
-UBool fIsStandardDigits;
-UnicodeString fExponent;
-UBool isStandardDigits() const;
-
-UnicodeString &formatDigits(
- const uint8_t *digits,
- int32_t count,
- const IntDigitCountRange &range,
- int32_t intField,
- FieldPositionHandler &handler,
- UnicodeString &appendTo) const;
-
-void setOtherDecimalFormatSymbols(const DecimalFormatSymbols &symbols);
-
-int32_t countChar32(
- const VisibleDigits &exponent,
- const DigitInterval &mantissaInterval,
- const SciFormatterOptions &options) const;
-
-UnicodeString &formatNaN(
- FieldPositionHandler &handler,
- UnicodeString &appendTo) const {
- return fNan.format(handler, appendTo);
-}
-
-int32_t countChar32ForNaN() const {
- return fNan.toString().countChar32();
-}
-
-UnicodeString &formatInfinity(
- FieldPositionHandler &handler,
- UnicodeString &appendTo) const {
- return fInfinity.format(handler, appendTo);
-}
-
-int32_t countChar32ForInfinity() const {
- return fInfinity.toString().countChar32();
-}
-
-UnicodeString &formatExponent(
- const VisibleDigits &digits,
- const DigitFormatterIntOptions &options,
- int32_t signField,
- int32_t intField,
- FieldPositionHandler &handler,
- UnicodeString &appendTo) const;
-
-int32_t countChar32(
- const DigitGrouping &grouping,
- const DigitInterval &interval,
- const DigitFormatterOptions &options) const;
-
-int32_t countChar32ForExponent(
- const VisibleDigits &exponent,
- const DigitFormatterIntOptions &options) const;
-
-};
-
-
-U_NAMESPACE_END
-#endif /* #if !UCONFIG_NO_FORMATTING */
-#endif // __DIGITFORMATTER_H__
diff --git a/deps/icu-small/source/i18n/digitgrouping.cpp b/deps/icu-small/source/i18n/digitgrouping.cpp
deleted file mode 100644
index cffa122b6ceaf6..00000000000000
--- a/deps/icu-small/source/i18n/digitgrouping.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-// © 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 name: digitgrouping.cpp
- */
-
-#include "unicode/utypes.h"
-
-#include "digitgrouping.h"
-#include "smallintformatter.h"
-
-U_NAMESPACE_BEGIN
-
-UBool DigitGrouping::isSeparatorAt(
- int32_t digitsLeftOfDecimal, int32_t digitPos) const {
- if (!isGroupingEnabled(digitsLeftOfDecimal) || digitPos < fGrouping) {
- return FALSE;
- }
- return ((digitPos - fGrouping) % getGrouping2() == 0);
-}
-
-int32_t DigitGrouping::getSeparatorCount(int32_t digitsLeftOfDecimal) const {
- if (!isGroupingEnabled(digitsLeftOfDecimal)) {
- return 0;
- }
- return (digitsLeftOfDecimal - 1 - fGrouping) / getGrouping2() + 1;
-}
-
-UBool DigitGrouping::isGroupingEnabled(int32_t digitsLeftOfDecimal) const {
- return (isGroupingUsed()
- && digitsLeftOfDecimal >= fGrouping + getMinGrouping());
-}
-
-UBool DigitGrouping::isNoGrouping(
- int32_t positiveValue, const IntDigitCountRange &range) const {
- return getSeparatorCount(
- SmallIntFormatter::estimateDigitCount(positiveValue, range)) == 0;
-}
-
-int32_t DigitGrouping::getGrouping2() const {
- return (fGrouping2 > 0 ? fGrouping2 : fGrouping);
-}
-
-int32_t DigitGrouping::getMinGrouping() const {
- return (fMinGrouping > 0 ? fMinGrouping : 1);
-}
-
-void
-DigitGrouping::clear() {
- fMinGrouping = 0;
- fGrouping = 0;
- fGrouping2 = 0;
-}
-
-U_NAMESPACE_END
diff --git a/deps/icu-small/source/i18n/digitgrouping.h b/deps/icu-small/source/i18n/digitgrouping.h
deleted file mode 100644
index f3f8679b879e95..00000000000000
--- a/deps/icu-small/source/i18n/digitgrouping.h
+++ /dev/null
@@ -1,112 +0,0 @@
-// © 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.
-*******************************************************************************
-* digitgrouping.h
-*
-* created on: 2015jan6
-* created by: Travis Keep
-*/
-
-#ifndef __DIGITGROUPING_H__
-#define __DIGITGROUPING_H__
-
-#include "unicode/uobject.h"
-#include "unicode/utypes.h"
-
-U_NAMESPACE_BEGIN
-
-class IntDigitCountRange;
-
-/**
- * The digit grouping policy.
- */
-class U_I18N_API DigitGrouping : public UMemory {
-public:
- /**
- * Default is no digit grouping.
- */
- DigitGrouping() : fGrouping(0), fGrouping2(0), fMinGrouping(0) { }
-
- /**
- * Returns TRUE if this object is equal to rhs.
- */
- UBool equals(const DigitGrouping &rhs) const {
- return ((fGrouping == rhs.fGrouping) &&
- (fGrouping2 == rhs.fGrouping2) &&
- (fMinGrouping == rhs.fMinGrouping));
- }
-
- /**
- * Returns true if a separator is needed after a particular digit.
- * @param digitsLeftOfDecimal the total count of digits left of the
- * decimal.
- * @param digitPos 0 is the one's place; 1 is the 10's place; -1 is the
- * 1/10's place etc.
- */
- UBool isSeparatorAt(int32_t digitsLeftOfDecimal, int32_t digitPos) const;
-
- /**
- * Returns the total number of separators to be used to format a particular
- * number.
- * @param digitsLeftOfDecimal the total number of digits to the left of
- * the decimal.
- */
- int32_t getSeparatorCount(int32_t digitsLeftOfDecimal) const;
-
- /**
- * Returns true if grouping is used FALSE otherwise. When
- * isGroupingUsed() returns FALSE; isSeparatorAt always returns FALSE
- * and getSeparatorCount always returns 0.
- */
- UBool isGroupingUsed() const { return fGrouping > 0; }
-
- /**
- * Returns TRUE if this instance would not add grouping separators
- * when formatting value using the given constraint on digit count.
- *
- * @param value the value to format.
- * @param range the minimum and maximum digits for formatting value.
- */
- UBool isNoGrouping(
- int32_t positiveValue, const IntDigitCountRange &range) const;
-
- /**
- * Clears this instance so that digit grouping is not in effect.
- */
- void clear();
-
-public:
-
- /**
- * Primary grouping size. A value of 0, the default, or a negative
- * number causes isGroupingUsed() to return FALSE.
- */
- int32_t fGrouping;
-
- /**
- * Secondary grouping size. If > 0, this size is used instead of
- * 'fGrouping' for all but the group just to the left of the decimal
- * point. The default value of 0, or a negative value indicates that
- * there is no secondary grouping size.
- */
- int32_t fGrouping2;
-
- /**
- * If set (that is > 0), uses no grouping separators if fewer than
- * (fGrouping + fMinGrouping) digits appear left of the decimal place.
- * The default value for this field is 0.
- */
- int32_t fMinGrouping;
-private:
- UBool isGroupingEnabled(int32_t digitsLeftOfDecimal) const;
- int32_t getGrouping2() const;
- int32_t getMinGrouping() const;
-};
-
-U_NAMESPACE_END
-
-#endif // __DIGITGROUPING_H__
diff --git a/deps/icu-small/source/i18n/digitinterval.cpp b/deps/icu-small/source/i18n/digitinterval.cpp
deleted file mode 100644
index 32d952e0267950..00000000000000
--- a/deps/icu-small/source/i18n/digitinterval.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-// © 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 name: digitinterval.cpp
- */
-
-#include "unicode/utypes.h"
-
-#include "digitinterval.h"
-
-U_NAMESPACE_BEGIN
-
-void DigitInterval::expandToContain(const DigitInterval &rhs) {
- if (fSmallestInclusive > rhs.fSmallestInclusive) {
- fSmallestInclusive = rhs.fSmallestInclusive;
- }
- if (fLargestExclusive < rhs.fLargestExclusive) {
- fLargestExclusive = rhs.fLargestExclusive;
- }
-}
-
-void DigitInterval::shrinkToFitWithin(const DigitInterval &rhs) {
- if (fSmallestInclusive < rhs.fSmallestInclusive) {
- fSmallestInclusive = rhs.fSmallestInclusive;
- }
- if (fLargestExclusive > rhs.fLargestExclusive) {
- fLargestExclusive = rhs.fLargestExclusive;
- }
-}
-
-void DigitInterval::setIntDigitCount(int32_t count) {
- fLargestExclusive = count < 0 ? INT32_MAX : count;
-}
-
-void DigitInterval::setFracDigitCount(int32_t count) {
- fSmallestInclusive = count < 0 ? INT32_MIN : -count;
-}
-
-void DigitInterval::expandToContainDigit(int32_t digitExponent) {
- if (fLargestExclusive <= digitExponent) {
- fLargestExclusive = digitExponent + 1;
- } else if (fSmallestInclusive > digitExponent) {
- fSmallestInclusive = digitExponent;
- }
-}
-
-UBool DigitInterval::contains(int32_t x) const {
- return (x < fLargestExclusive && x >= fSmallestInclusive);
-}
-
-
-U_NAMESPACE_END
diff --git a/deps/icu-small/source/i18n/digitinterval.h b/deps/icu-small/source/i18n/digitinterval.h
deleted file mode 100644
index 95d406da206f4c..00000000000000
--- a/deps/icu-small/source/i18n/digitinterval.h
+++ /dev/null
@@ -1,159 +0,0 @@
-// © 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.
-*******************************************************************************
-* digitinterval.h
-*
-* created on: 2015jan6
-* created by: Travis Keep
-*/
-
-#ifndef __DIGITINTERVAL_H__
-#define __DIGITINTERVAL_H__
-
-#include "unicode/uobject.h"
-#include "unicode/utypes.h"
-
-U_NAMESPACE_BEGIN
-
-/**
- * An interval of digits.
- * DigitIntervals are for fixed point formatting. A DigitInterval specifies
- * zero or more integer digits and zero or more fractional digits. This class
- * specifies particular digits in a number by their power of 10. For example,
- * the digit position just to the left of the decimal is 0, and the digit
- * position just left of that is 1. The digit position just to the right of
- * the decimal is -1. The digit position just to the right of that is -2.
- */
-class U_I18N_API DigitInterval : public UMemory {
-public:
-
- /**
- * Spans all integer and fraction digits
- */
- DigitInterval()
- : fLargestExclusive(INT32_MAX), fSmallestInclusive(INT32_MIN) { }
-
-
- /**
- * Makes this instance span all digits.
- */
- void clear() {
- fLargestExclusive = INT32_MAX;
- fSmallestInclusive = INT32_MIN;
- }
-
- /**
- * Returns TRUE if this interval contains this digit position.
- */
- UBool contains(int32_t digitPosition) const;
-
- /**
- * Returns true if this object is the same as rhs.
- */
- UBool equals(const DigitInterval &rhs) const {
- return ((fLargestExclusive == rhs.fLargestExclusive) &&
- (fSmallestInclusive == rhs.fSmallestInclusive));
- }
-
- /**
- * Expand this interval so that it contains all of rhs.
- */
- void expandToContain(const DigitInterval &rhs);
-
- /**
- * Shrink this interval so that it contains no more than rhs.
- */
- void shrinkToFitWithin(const DigitInterval &rhs);
-
- /**
- * Expand this interval as necessary to contain digit with given exponent
- * After this method returns, this interval is guaranteed to contain
- * digitExponent.
- */
- void expandToContainDigit(int32_t digitExponent);
-
- /**
- * Changes the number of digits to the left of the decimal point that
- * this interval spans. If count is negative, it means span all digits
- * to the left of the decimal point.
- */
- void setIntDigitCount(int32_t count);
-
- /**
- * Changes the number of digits to the right of the decimal point that
- * this interval spans. If count is negative, it means span all digits
- * to the right of the decimal point.
- */
- void setFracDigitCount(int32_t count);
-
- /**
- * Sets the least significant inclusive value to smallest. If smallest >= 0
- * then least significant inclusive value becomes 0.
- */
- void setLeastSignificantInclusive(int32_t smallest) {
- fSmallestInclusive = smallest < 0 ? smallest : 0;
- }
-
- /**
- * Sets the most significant exclusive value to largest.
- * If largest <= 0 then most significant exclusive value becomes 0.
- */
- void setMostSignificantExclusive(int32_t largest) {
- fLargestExclusive = largest > 0 ? largest : 0;
- }
-
- /**
- * If returns 8, the most significant digit in interval is the 10^7 digit.
- * Returns INT32_MAX if this interval spans all digits to left of
- * decimal point.
- */
- int32_t getMostSignificantExclusive() const {
- return fLargestExclusive;
- }
-
- /**
- * Returns number of digits to the left of the decimal that this
- * interval includes. This is a synonym for getMostSignificantExclusive().
- */
- int32_t getIntDigitCount() const {
- return fLargestExclusive;
- }
-
- /**
- * Returns number of digits to the right of the decimal that this
- * interval includes.
- */
- int32_t getFracDigitCount() const {
- return fSmallestInclusive == INT32_MIN ? INT32_MAX : -fSmallestInclusive;
- }
-
- /**
- * Returns the total number of digits that this interval spans.
- * Caution: If this interval spans all digits to the left or right of
- * decimal point instead of some fixed number, then what length()
- * returns is undefined.
- */
- int32_t length() const {
- return fLargestExclusive - fSmallestInclusive;
- }
-
- /**
- * If returns -3, the least significant digit in interval is the 10^-3
- * digit. Returns INT32_MIN if this interval spans all digits to right of
- * decimal point.
- */
- int32_t getLeastSignificantInclusive() const {
- return fSmallestInclusive;
- }
-private:
- int32_t fLargestExclusive;
- int32_t fSmallestInclusive;
-};
-
-U_NAMESPACE_END
-
-#endif // __DIGITINTERVAL_H__
diff --git a/deps/icu-small/source/i18n/digitlst.cpp b/deps/icu-small/source/i18n/digitlst.cpp
deleted file mode 100644
index 37760defd708bc..00000000000000
--- a/deps/icu-small/source/i18n/digitlst.cpp
+++ /dev/null
@@ -1,1143 +0,0 @@
-// © 2016 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html
-/*
-**********************************************************************
-* Copyright (C) 1997-2015, International Business Machines
-* Corporation and others. All Rights Reserved.
-**********************************************************************
-*
-* File DIGITLST.CPP
-*
-* Modification History:
-*
-* Date Name Description
-* 03/21/97 clhuang Converted from java.
-* 03/21/97 clhuang Implemented with new APIs.
-* 03/27/97 helena Updated to pass the simple test after code review.
-* 03/31/97 aliu Moved isLONG_MIN to here, and fixed it.
-* 04/15/97 aliu Changed MAX_COUNT to DBL_DIG. Changed Digit to char.
-* Reworked representation by replacing fDecimalAt
-* with fExponent.
-* 04/16/97 aliu Rewrote set() and getDouble() to use sprintf/atof
-* to do digit conversion.
-* 09/09/97 aliu Modified for exponential notation support.
-* 08/02/98 stephen Added nearest/even rounding
-* Fixed bug in fitsIntoLong
-******************************************************************************
-*/
-
-#if defined(__CYGWIN__) && !defined(_GNU_SOURCE)
-#define _GNU_SOURCE
-#endif
-
-#include "digitlst.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "unicode/putil.h"
-#include "charstr.h"
-#include "cmemory.h"
-#include "cstring.h"
-#include "mutex.h"
-#include "putilimp.h"
-#include "uassert.h"
-#include "digitinterval.h"
-#include "ucln_in.h"
-#include "umutex.h"
-#include "double-conversion.h"
-#include
-#include
-#include
-#include
-#include
-
-using icu::double_conversion::DoubleToStringConverter;
-
-#if !defined(U_USE_STRTOD_L)
-# if U_PLATFORM_USES_ONLY_WIN32_API
-# define U_USE_STRTOD_L 1
-# define U_HAVE_XLOCALE_H 0
-# elif defined(U_HAVE_STRTOD_L)
-# define U_USE_STRTOD_L U_HAVE_STRTOD_L
-# else
-# define U_USE_STRTOD_L 0
-# endif
-#endif
-
-#if U_USE_STRTOD_L
-# if U_HAVE_XLOCALE_H
-# include
-# else
-# include
-# endif
-#endif
-
-// ***************************************************************************
-// class DigitList
-// A wrapper onto decNumber.
-// Used to be standalone.
-// ***************************************************************************
-
-/**
- * This is the zero digit. The base for the digits returned by getDigit()
- * Note that it is the platform invariant digit, and is not Unicode.
- */
-#define kZero '0'
-
-
-/* Only for 32 bit numbers. Ignore the negative sign. */
-//static const char LONG_MIN_REP[] = "2147483648";
-//static const char I64_MIN_REP[] = "9223372036854775808";
-
-
-U_NAMESPACE_BEGIN
-
-// -------------------------------------
-// default constructor
-
-DigitList::DigitList()
-{
- uprv_decContextDefault(&fContext, DEC_INIT_BASE);
- fContext.traps = 0;
- uprv_decContextSetRounding(&fContext, DEC_ROUND_HALF_EVEN);
- fContext.digits = fStorage.getCapacity();
-
- fDecNumber = fStorage.getAlias();
- uprv_decNumberZero(fDecNumber);
-
- internalSetDouble(0.0);
-}
-
-// -------------------------------------
-
-DigitList::~DigitList()
-{
-}
-
-// -------------------------------------
-// copy constructor
-
-DigitList::DigitList(const DigitList &other)
-{
- fDecNumber = fStorage.getAlias();
- *this = other;
-}
-
-
-// -------------------------------------
-// assignment operator
-
-DigitList&
-DigitList::operator=(const DigitList& other)
-{
- if (this != &other)
- {
- uprv_memcpy(&fContext, &other.fContext, sizeof(decContext));
-
- if (other.fStorage.getCapacity() > fStorage.getCapacity()) {
- fDecNumber = fStorage.resize(other.fStorage.getCapacity());
- }
- // Always reset the fContext.digits, even if fDecNumber was not reallocated,
- // because above we copied fContext from other.fContext.
- fContext.digits = fStorage.getCapacity();
- uprv_decNumberCopy(fDecNumber, other.fDecNumber);
-
- {
- // fDouble is lazily created and cached.
- // Avoid potential races with that happening with other.fDouble
- // while we are doing the assignment.
- Mutex mutex;
-
- if(other.fHave==kDouble) {
- fUnion.fDouble = other.fUnion.fDouble;
- }
- fHave = other.fHave;
- }
- }
- return *this;
-}
-
-// -------------------------------------
-// operator == (does not exactly match the old DigitList function)
-
-UBool
-DigitList::operator==(const DigitList& that) const
-{
- if (this == &that) {
- return TRUE;
- }
- decNumber n; // Has space for only a none digit value.
- decContext c;
- uprv_decContextDefault(&c, DEC_INIT_BASE);
- c.digits = 1;
- c.traps = 0;
-
- uprv_decNumberCompare(&n, this->fDecNumber, that.fDecNumber, &c);
- UBool result = decNumberIsZero(&n);
- return result;
-}
-
-// -------------------------------------
-// comparison function. Returns
-// Not Comparable : -2
-// < : -1
-// == : 0
-// > : +1
-int32_t DigitList::compare(const DigitList &other) {
- decNumber result;
- int32_t savedDigits = fContext.digits;
- fContext.digits = 1;
- uprv_decNumberCompare(&result, this->fDecNumber, other.fDecNumber, &fContext);
- fContext.digits = savedDigits;
- if (decNumberIsZero(&result)) {
- return 0;
- } else if (decNumberIsSpecial(&result)) {
- return -2;
- } else if (result.bits & DECNEG) {
- return -1;
- } else {
- return 1;
- }
-}
-
-
-// -------------------------------------
-// Reduce - remove trailing zero digits.
-void
-DigitList::reduce() {
- uprv_decNumberReduce(fDecNumber, fDecNumber, &fContext);
-}
-
-
-// -------------------------------------
-// trim - remove trailing fraction zero digits.
-void
-DigitList::trim() {
- uprv_decNumberTrim(fDecNumber);
-}
-
-// -------------------------------------
-// Resets the digit list; sets all the digits to zero.
-
-void
-DigitList::clear()
-{
- uprv_decNumberZero(fDecNumber);
- uprv_decContextSetRounding(&fContext, DEC_ROUND_HALF_EVEN);
- internalSetDouble(0.0);
-}
-
-
-/**
- * Formats a int64_t number into a base 10 string representation, and NULL terminates it.
- * @param number The number to format
- * @param outputStr The string to output to. Must be at least MAX_DIGITS+2 in length (21),
- * to hold the longest int64_t value.
- * @return the number of digits written, not including the sign.
- */
-static int32_t
-formatBase10(int64_t number, char *outputStr) {
- // The number is output backwards, starting with the LSD.
- // Fill the buffer from the far end. After the number is complete,
- // slide the string contents to the front.
-
- const int32_t MAX_IDX = MAX_DIGITS+2;
- int32_t destIdx = MAX_IDX;
- outputStr[--destIdx] = 0;
-
- int64_t n = number;
- if (number < 0) { // Negative numbers are slightly larger than a postive
- outputStr[--destIdx] = (char)(-(n % 10) + kZero);
- n /= -10;
- }
- do {
- outputStr[--destIdx] = (char)(n % 10 + kZero);
- n /= 10;
- } while (n > 0);
-
- if (number < 0) {
- outputStr[--destIdx] = '-';
- }
-
- // Slide the number to the start of the output str
- U_ASSERT(destIdx >= 0);
- int32_t length = MAX_IDX - destIdx;
- uprv_memmove(outputStr, outputStr+MAX_IDX-length, length);
-
- return length;
-}
-
-
-// -------------------------------------
-//
-// setRoundingMode()
-// For most modes, the meaning and names are the same between the decNumber library
-// (which DigitList follows) and the ICU Formatting Rounding Mode values.
-// The flag constants are different, however.
-//
-// Note that ICU's kRoundingUnnecessary is not implemented directly by DigitList.
-// This mode, inherited from Java, means that numbers that would not format exactly
-// will return an error when formatting is attempted.
-
-void
-DigitList::setRoundingMode(DecimalFormat::ERoundingMode m) {
- enum rounding r;
-
- switch (m) {
- case DecimalFormat::kRoundCeiling: r = DEC_ROUND_CEILING; break;
- case DecimalFormat::kRoundFloor: r = DEC_ROUND_FLOOR; break;
- case DecimalFormat::kRoundDown: r = DEC_ROUND_DOWN; break;
- case DecimalFormat::kRoundUp: r = DEC_ROUND_UP; break;
- case DecimalFormat::kRoundHalfEven: r = DEC_ROUND_HALF_EVEN; break;
- case DecimalFormat::kRoundHalfDown: r = DEC_ROUND_HALF_DOWN; break;
- case DecimalFormat::kRoundHalfUp: r = DEC_ROUND_HALF_UP; break;
- case DecimalFormat::kRoundUnnecessary: r = DEC_ROUND_HALF_EVEN; break;
- default:
- // TODO: how to report the problem?
- // Leave existing mode unchanged.
- r = uprv_decContextGetRounding(&fContext);
- }
- uprv_decContextSetRounding(&fContext, r);
-
-}
-
-
-// -------------------------------------
-
-void
-DigitList::setPositive(UBool s) {
- if (s) {
- fDecNumber->bits &= ~DECNEG;
- } else {
- fDecNumber->bits |= DECNEG;
- }
- internalClear();
-}
-// -------------------------------------
-
-void
-DigitList::setDecimalAt(int32_t d) {
- U_ASSERT((fDecNumber->bits & DECSPECIAL) == 0); // Not Infinity or NaN
- U_ASSERT(d-1>-999999999);
- U_ASSERT(d-1< 999999999);
- int32_t adjustedDigits = fDecNumber->digits;
- if (decNumberIsZero(fDecNumber)) {
- // Account for difference in how zero is represented between DigitList & decNumber.
- adjustedDigits = 0;
- }
- fDecNumber->exponent = d - adjustedDigits;
- internalClear();
-}
-
-int32_t
-DigitList::getDecimalAt() {
- U_ASSERT((fDecNumber->bits & DECSPECIAL) == 0); // Not Infinity or NaN
- if (decNumberIsZero(fDecNumber) || ((fDecNumber->bits & DECSPECIAL) != 0)) {
- return fDecNumber->exponent; // Exponent should be zero for these cases.
- }
- return fDecNumber->exponent + fDecNumber->digits;
-}
-
-void
-DigitList::setCount(int32_t c) {
- U_ASSERT(c <= fContext.digits);
- if (c == 0) {
- // For a value of zero, DigitList sets all fields to zero, while
- // decNumber keeps one digit (with that digit being a zero)
- c = 1;
- fDecNumber->lsu[0] = 0;
- }
- fDecNumber->digits = c;
- internalClear();
-}
-
-int32_t
-DigitList::getCount() const {
- if (decNumberIsZero(fDecNumber) && fDecNumber->exponent==0) {
- // The extra test for exponent==0 is needed because parsing sometimes appends
- // zero digits. It's bogus, decimalFormatter parsing needs to be cleaned up.
- return 0;
- } else {
- return fDecNumber->digits;
- }
-}
-
-void
-DigitList::setDigit(int32_t i, char v) {
- int32_t count = fDecNumber->digits;
- U_ASSERT(i='0' && v<='9');
- v &= 0x0f;
- fDecNumber->lsu[count-i-1] = v;
- internalClear();
-}
-
-char
-DigitList::getDigit(int32_t i) {
- int32_t count = fDecNumber->digits;
- U_ASSERT(ilsu[count-i-1] + '0';
-}
-
-// copied from DigitList::getDigit()
-uint8_t
-DigitList::getDigitValue(int32_t i) {
- int32_t count = fDecNumber->digits;
- U_ASSERT(ilsu[count-i-1];
-}
-
-// -------------------------------------
-// Appends the digit to the digit list if it's not out of scope.
-// Ignores the digit, otherwise.
-//
-// This function is horribly inefficient to implement with decNumber because
-// the digits are stored least significant first, which requires moving all
-// existing digits down one to make space for the new one to be appended.
-//
-void
-DigitList::append(char digit)
-{
- U_ASSERT(digit>='0' && digit<='9');
- // Ignore digits which exceed the precision we can represent
- // And don't fix for larger precision. Fix callers instead.
- if (decNumberIsZero(fDecNumber)) {
- // Zero needs to be special cased because of the difference in the way
- // that the old DigitList and decNumber represent it.
- // digit cout was zero for digitList, is one for decNumber
- fDecNumber->lsu[0] = digit & 0x0f;
- fDecNumber->digits = 1;
- fDecNumber->exponent--; // To match the old digit list implementation.
- } else {
- int32_t nDigits = fDecNumber->digits;
- if (nDigits < fContext.digits) {
- int i;
- for (i=nDigits; i>0; i--) {
- fDecNumber->lsu[i] = fDecNumber->lsu[i-1];
- }
- fDecNumber->lsu[0] = digit & 0x0f;
- fDecNumber->digits++;
- // DigitList emulation - appending doesn't change the magnitude of existing
- // digits. With decNumber's decimal being after the
- // least signficant digit, we need to adjust the exponent.
- fDecNumber->exponent--;
- }
- }
- internalClear();
-}
-
-// -------------------------------------
-
-/**
- * Currently, getDouble() depends on strtod() to do its conversion.
- *
- * WARNING!!
- * This is an extremely costly function. ~1/2 of the conversion time
- * can be linked to this function.
- */
-double
-DigitList::getDouble() const
-{
- {
- Mutex mutex;
- if (fHave == kDouble) {
- return fUnion.fDouble;
- }
- }
-
- double tDouble = 0.0;
- if (isZero()) {
- tDouble = 0.0;
- if (decNumberIsNegative(fDecNumber)) {
- tDouble /= -1;
- }
- } else if (isInfinite()) {
- if (std::numeric_limits::has_infinity) {
- tDouble = std::numeric_limits::infinity();
- } else {
- tDouble = std::numeric_limits::max();
- }
- if (!isPositive()) {
- tDouble = -tDouble; //this was incorrectly "-fDouble" originally.
- }
- } else {
- MaybeStackArray s;
- // Note: 14 is a magic constant from the decNumber library documentation,
- // the max number of extra characters beyond the number of digits
- // needed to represent the number in string form. Add a few more
- // for the additional digits we retain.
-
- // Round down to appx. double precision, if the number is longer than that.
- // Copy the number first, so that we don't modify the original.
- if (getCount() > MAX_DBL_DIGITS + 3) {
- DigitList numToConvert(*this);
- numToConvert.reduce(); // Removes any trailing zeros, so that digit count is good.
- numToConvert.round(MAX_DBL_DIGITS+3);
- uprv_decNumberToString(numToConvert.fDecNumber, s.getAlias());
- // TODO: how many extra digits should be included for an accurate conversion?
- } else {
- uprv_decNumberToString(this->fDecNumber, s.getAlias());
- }
- U_ASSERT(uprv_strlen(&s[0]) < MAX_DBL_DIGITS+18);
-
- char *end = NULL;
- tDouble = decimalStrToDouble(s.getAlias(), &end);
- }
- {
- Mutex mutex;
- DigitList *nonConstThis = const_cast(this);
- nonConstThis->internalSetDouble(tDouble);
- }
- return tDouble;
-}
-
-#if U_USE_STRTOD_L && U_PLATFORM_USES_ONLY_WIN32_API
-# define locale_t _locale_t
-# define freelocale _free_locale
-# define strtod_l _strtod_l
-#endif
-
-#if U_USE_STRTOD_L
-static locale_t gCLocale = (locale_t)0;
-#endif
-static icu::UInitOnce gCLocaleInitOnce = U_INITONCE_INITIALIZER;
-
-U_CDECL_BEGIN
-// Cleanup callback func
-static UBool U_CALLCONV digitList_cleanup(void)
-{
-#if U_USE_STRTOD_L
- if (gCLocale != (locale_t)0) {
- freelocale(gCLocale);
- }
-#endif
- return TRUE;
-}
-// C Locale initialization func
-static void U_CALLCONV initCLocale(void) {
- ucln_i18n_registerCleanup(UCLN_I18N_DIGITLIST, digitList_cleanup);
-#if U_USE_STRTOD_L
-# if U_PLATFORM_USES_ONLY_WIN32_API
- gCLocale = _create_locale(LC_ALL, "C");
-# else
- gCLocale = newlocale(LC_ALL_MASK, "C", (locale_t)0);
-# endif
-#endif
-}
-U_CDECL_END
-
-double
-DigitList::decimalStrToDouble(char *decstr, char **end) {
- umtx_initOnce(gCLocaleInitOnce, &initCLocale);
-#if U_USE_STRTOD_L
- return strtod_l(decstr, end, gCLocale);
-#else
- char *decimalPt = strchr(decstr, '.');
- if (decimalPt) {
- // We need to know the decimal separator character that will be used with strtod().
- // Depends on the C runtime global locale.
- // Most commonly is '.'
- char rep[MAX_DIGITS];
- sprintf(rep, "%+1.1f", 1.0);
- *decimalPt = rep[2];
- }
- return uprv_strtod(decstr, end);
-#endif
-}
-
-// -------------------------------------
-
-/**
- * convert this number to an int32_t. Round if there is a fractional part.
- * Return zero if the number cannot be represented.
- */
-int32_t DigitList::getLong() /*const*/
-{
- int32_t result = 0;
- if (getUpperExponent() > 10) {
- // Overflow, absolute value too big.
- return result;
- }
- if (fDecNumber->exponent != 0) {
- // Force to an integer, with zero exponent, rounding if necessary.
- // (decNumberToInt32 will only work if the exponent is exactly zero.)
- DigitList copy(*this);
- DigitList zero;
- uprv_decNumberQuantize(copy.fDecNumber, copy.fDecNumber, zero.fDecNumber, &fContext);
- result = uprv_decNumberToInt32(copy.fDecNumber, &fContext);
- } else {
- result = uprv_decNumberToInt32(fDecNumber, &fContext);
- }
- return result;
-}
-
-
-/**
- * convert this number to an int64_t. Truncate if there is a fractional part.
- * Return zero if the number cannot be represented.
- */
-int64_t DigitList::getInt64() /*const*/ {
- // TODO: fast conversion if fHave == fDouble
-
- // Truncate if non-integer.
- // Return 0 if out of range.
- // Range of in64_t is -9223372036854775808 to 9223372036854775807 (19 digits)
- //
- if (getUpperExponent() > 19) {
- // Overflow, absolute value too big.
- return 0;
- }
-
- // The number of integer digits may differ from the number of digits stored
- // in the decimal number.
- // for 12.345 numIntDigits = 2, number->digits = 5
- // for 12E4 numIntDigits = 6, number->digits = 2
- // The conversion ignores the fraction digits in the first case,
- // and fakes up extra zero digits in the second.
- // TODO: It would be faster to store a table of powers of ten to multiply by
- // instead of looping over zero digits, multiplying each time.
-
- int32_t numIntDigits = getUpperExponent();
- uint64_t value = 0;
- for (int32_t i = 0; i < numIntDigits; i++) {
- // Loop is iterating over digits starting with the most significant.
- // Numbers are stored with the least significant digit at index zero.
- int32_t digitIndex = fDecNumber->digits - i - 1;
- int32_t v = (digitIndex >= 0) ? fDecNumber->lsu[digitIndex] : 0;
- value = value * (uint64_t)10 + (uint64_t)v;
- }
-
- if (decNumberIsNegative(fDecNumber)) {
- value = ~value;
- value += 1;
- }
- int64_t svalue = (int64_t)value;
-
- // Check overflow. It's convenient that the MSD is 9 only on overflow, the amount of
- // overflow can't wrap too far. The test will also fail -0, but
- // that does no harm; the right answer is 0.
- if (numIntDigits == 19) {
- if (( decNumberIsNegative(fDecNumber) && svalue>0) ||
- (!decNumberIsNegative(fDecNumber) && svalue<0)) {
- svalue = 0;
- }
- }
-
- return svalue;
-}
-
-
-/**
- * Return a string form of this number.
- * Format is as defined by the decNumber library, for interchange of
- * decimal numbers.
- */
-void DigitList::getDecimal(CharString &str, UErrorCode &status) {
- if (U_FAILURE(status)) {
- return;
- }
-
- // A decimal number in string form can, worst case, be 14 characters longer
- // than the number of digits. So says the decNumber library doc.
- int32_t maxLength = fDecNumber->digits + 14;
- int32_t capacity = 0;
- char *buffer = str.clear().getAppendBuffer(maxLength, 0, capacity, status);
- if (U_FAILURE(status)) {
- return; // Memory allocation error on growing the string.
- }
- U_ASSERT(capacity >= maxLength);
- uprv_decNumberToString(this->fDecNumber, buffer);
- U_ASSERT((int32_t)uprv_strlen(buffer) <= maxLength);
- str.append(buffer, -1, status);
-}
-
-/**
- * Return true if this is an integer value that can be held
- * by an int32_t type.
- */
-UBool
-DigitList::fitsIntoLong(UBool ignoreNegativeZero) /*const*/
-{
- if (decNumberIsSpecial(this->fDecNumber)) {
- // NaN or Infinity. Does not fit in int32.
- return FALSE;
- }
- uprv_decNumberTrim(this->fDecNumber);
- if (fDecNumber->exponent < 0) {
- // Number contains fraction digits.
- return FALSE;
- }
- if (decNumberIsZero(this->fDecNumber) && !ignoreNegativeZero &&
- (fDecNumber->bits & DECNEG) != 0) {
- // Negative Zero, not ingored. Cannot represent as a long.
- return FALSE;
- }
- if (getUpperExponent() < 10) {
- // The number is 9 or fewer digits.
- // The max and min int32 are 10 digts, so this number fits.
- // This is the common case.
- return TRUE;
- }
-
- // TODO: Should cache these constants; construction is relatively costly.
- // But not of huge consequence; they're only needed for 10 digit ints.
- UErrorCode status = U_ZERO_ERROR;
- DigitList min32; min32.set("-2147483648", status);
- if (this->compare(min32) < 0) {
- return FALSE;
- }
- DigitList max32; max32.set("2147483647", status);
- if (this->compare(max32) > 0) {
- return FALSE;
- }
- if (U_FAILURE(status)) {
- return FALSE;
- }
- return true;
-}
-
-
-
-/**
- * Return true if the number represented by this object can fit into
- * a long.
- */
-UBool
-DigitList::fitsIntoInt64(UBool ignoreNegativeZero) /*const*/
-{
- if (decNumberIsSpecial(this->fDecNumber)) {
- // NaN or Infinity. Does not fit in int32.
- return FALSE;
- }
- uprv_decNumberTrim(this->fDecNumber);
- if (fDecNumber->exponent < 0) {
- // Number contains fraction digits.
- return FALSE;
- }
- if (decNumberIsZero(this->fDecNumber) && !ignoreNegativeZero &&
- (fDecNumber->bits & DECNEG) != 0) {
- // Negative Zero, not ingored. Cannot represent as a long.
- return FALSE;
- }
- if (getUpperExponent() < 19) {
- // The number is 18 or fewer digits.
- // The max and min int64 are 19 digts, so this number fits.
- // This is the common case.
- return TRUE;
- }
-
- // TODO: Should cache these constants; construction is relatively costly.
- // But not of huge consequence; they're only needed for 19 digit ints.
- UErrorCode status = U_ZERO_ERROR;
- DigitList min64; min64.set("-9223372036854775808", status);
- if (this->compare(min64) < 0) {
- return FALSE;
- }
- DigitList max64; max64.set("9223372036854775807", status);
- if (this->compare(max64) > 0) {
- return FALSE;
- }
- if (U_FAILURE(status)) {
- return FALSE;
- }
- return true;
-}
-
-
-// -------------------------------------
-
-void
-DigitList::set(int32_t source)
-{
- set((int64_t)source);
- internalSetDouble(source);
-}
-
-// -------------------------------------
-/**
- * Set an int64, via decnumber
- */
-void
-DigitList::set(int64_t source)
-{
- char str[MAX_DIGITS+2]; // Leave room for sign and trailing nul.
- formatBase10(source, str);
- U_ASSERT(uprv_strlen(str) < sizeof(str));
-
- uprv_decNumberFromString(fDecNumber, str, &fContext);
- internalSetDouble(static_cast(source));
-}
-
-// -------------------------------------
-/**
- * Set the DigitList from a decimal number string.
- *
- * The incoming string _must_ be nul terminated, even though it is arriving
- * as a StringPiece because that is what the decNumber library wants.
- * We can get away with this for an internal function; it would not
- * be acceptable for a public API.
- */
-void
-DigitList::set(StringPiece source, UErrorCode &status, uint32_t /*fastpathBits*/) {
- if (U_FAILURE(status)) {
- return;
- }
-
-#if 0
- if(fastpathBits==(kFastpathOk|kNoDecimal)) {
- int32_t size = source.size();
- const char *data = source.data();
- int64_t r = 0;
- int64_t m = 1;
- // fast parse
- while(size>0) {
- char ch = data[--size];
- if(ch=='+') {
- break;
- } else if(ch=='-') {
- r = -r;
- break;
- } else {
- int64_t d = ch-'0';
- //printf("CH[%d]=%c, %d, *=%d\n", size,ch, (int)d, (int)m);
- r+=(d)*m;
- m *= 10;
- }
- }
- //printf("R=%d\n", r);
- set(r);
- } else
-#endif
- {
- // Figure out a max number of digits to use during the conversion, and
- // resize the number up if necessary.
- int32_t numDigits = source.length();
- if (numDigits > fContext.digits) {
- // fContext.digits == fStorage.getCapacity()
- decNumber *t = fStorage.resize(numDigits, fStorage.getCapacity());
- if (t == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- fDecNumber = t;
- fContext.digits = numDigits;
- }
-
- fContext.status = 0;
- uprv_decNumberFromString(fDecNumber, source.data(), &fContext);
- if ((fContext.status & DEC_Conversion_syntax) != 0) {
- status = U_DECIMAL_NUMBER_SYNTAX_ERROR;
- }
- }
- internalClear();
-}
-
-/**
- * Set the digit list to a representation of the given double value.
- * This method supports both fixed-point and exponential notation.
- * @param source Value to be converted.
- */
-void
-DigitList::set(double source)
-{
- // for now, simple implementation; later, do proper IEEE stuff
- char rep[MAX_DIGITS + 8]; // Extra space for '+', '.', e+NNN, and '\0' (actually +8 is enough)
-
- // Generate a representation of the form /[+-][0-9].[0-9]+e[+-][0-9]+/
- // Can also generate /[+-]nan/ or /[+-]inf/
- // TODO: Use something other than sprintf() here, since it's behavior is somewhat platform specific.
- // That is why infinity is special cased here.
- if (uprv_isInfinite(source)) {
- if (uprv_isNegativeInfinity(source)) {
- uprv_strcpy(rep,"-inf"); // Handle negative infinity
- } else {
- uprv_strcpy(rep,"inf");
- }
- } else if (uprv_isNaN(source)) {
- uprv_strcpy(rep, "NaN");
- } else {
- bool sign;
- int32_t length;
- int32_t point;
- DoubleToStringConverter::DoubleToAscii(
- source,
- DoubleToStringConverter::DtoaMode::SHORTEST,
- 0,
- rep + 1,
- sizeof(rep),
- &sign,
- &length,
- &point
- );
-
- // Convert the raw buffer into a string for decNumber
- int32_t power = point - length;
- if (sign) {
- rep[0] = '-';
- } else {
- rep[0] = '0';
- }
- length++;
- rep[length++] = 'E';
- if (power < 0) {
- rep[length++] = '-';
- power = -power;
- } else {
- rep[length++] = '+';
- }
- if (power < 10) {
- rep[length++] = power + '0';
- } else if (power < 100) {
- rep[length++] = (power / 10) + '0';
- rep[length++] = (power % 10) + '0';
- } else {
- U_ASSERT(power < 1000);
- rep[length + 2] = (power % 10) + '0';
- power /= 10;
- rep[length + 1] = (power % 10) + '0';
- power /= 10;
- rep[length] = power + '0';
- length += 3;
- }
- rep[length++] = 0;
- }
- U_ASSERT(uprv_strlen(rep) < sizeof(rep));
-
- // uprv_decNumberFromString() will parse the string expecting '.' as a
- // decimal separator, however sprintf() can use ',' in certain locales.
- // Overwrite a ',' with '.' here before proceeding.
- char *decimalSeparator = strchr(rep, ',');
- if (decimalSeparator != NULL) {
- *decimalSeparator = '.';
- }
-
- // Create a decNumber from the string.
- uprv_decNumberFromString(fDecNumber, rep, &fContext);
- uprv_decNumberTrim(fDecNumber);
- internalSetDouble(source);
-}
-
-// -------------------------------------
-
-/*
- * Multiply
- * The number will be expanded if need be to retain full precision.
- * In practice, for formatting, multiply is by 10, 100 or 1000, so more digits
- * will not be required for this use.
- */
-void
-DigitList::mult(const DigitList &other, UErrorCode &status) {
- if (U_FAILURE(status)) {
- return;
- }
- fContext.status = 0;
- int32_t requiredDigits = this->digits() + other.digits();
- if (requiredDigits > fContext.digits) {
- reduce(); // Remove any trailing zeros
- int32_t requiredDigits = this->digits() + other.digits();
- ensureCapacity(requiredDigits, status);
- }
- uprv_decNumberMultiply(fDecNumber, fDecNumber, other.fDecNumber, &fContext);
- internalClear();
-}
-
-// -------------------------------------
-
-/*
- * Divide
- * The number will _not_ be expanded for inexact results.
- * TODO: probably should expand some, for rounding increments that
- * could add a few digits, e.g. .25, but not expand arbitrarily.
- */
-void
-DigitList::div(const DigitList &other, UErrorCode &status) {
- if (U_FAILURE(status)) {
- return;
- }
- uprv_decNumberDivide(fDecNumber, fDecNumber, other.fDecNumber, &fContext);
- internalClear();
-}
-
-// -------------------------------------
-
-/*
- * ensureCapacity. Grow the digit storage for the number if it's less than the requested
- * amount. Never reduce it. Available size is kept in fContext.digits.
- */
-void
-DigitList::ensureCapacity(int32_t requestedCapacity, UErrorCode &status) {
- if (U_FAILURE(status)) {
- return;
- }
- if (requestedCapacity <= 0) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return;
- }
- if (requestedCapacity > DEC_MAX_DIGITS) {
- // Don't report an error for requesting too much.
- // Arithemetic Results will be rounded to what can be supported.
- // At 999,999,999 max digits, exceeding the limit is not too likely!
- requestedCapacity = DEC_MAX_DIGITS;
- }
- if (requestedCapacity > fContext.digits) {
- decNumber *newBuffer = fStorage.resize(requestedCapacity, fStorage.getCapacity());
- if (newBuffer == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- fContext.digits = requestedCapacity;
- fDecNumber = newBuffer;
- }
-}
-
-// -------------------------------------
-
-/**
- * Round the representation to the given number of digits.
- * @param maximumDigits The maximum number of digits to be shown.
- * Upon return, count will be less than or equal to maximumDigits.
- */
-void
-DigitList::round(int32_t maximumDigits)
-{
- reduce();
- if (maximumDigits >= fDecNumber->digits) {
- return;
- }
- int32_t savedDigits = fContext.digits;
- fContext.digits = maximumDigits;
- uprv_decNumberPlus(fDecNumber, fDecNumber, &fContext);
- fContext.digits = savedDigits;
- uprv_decNumberTrim(fDecNumber);
- reduce();
- internalClear();
-}
-
-
-void
-DigitList::roundFixedPoint(int32_t maximumFractionDigits) {
- reduce(); // Remove trailing zeros.
- if (fDecNumber->exponent >= -maximumFractionDigits) {
- return;
- }
- decNumber scale; // Dummy decimal number, but with the desired number of
- uprv_decNumberZero(&scale); // fraction digits.
- scale.exponent = -maximumFractionDigits;
- scale.lsu[0] = 1;
-
- uprv_decNumberQuantize(fDecNumber, fDecNumber, &scale, &fContext);
- reduce();
- internalClear();
-}
-
-// -------------------------------------
-
-void
-DigitList::toIntegralValue() {
- uprv_decNumberToIntegralValue(fDecNumber, fDecNumber, &fContext);
-}
-
-
-// -------------------------------------
-UBool
-DigitList::isZero() const
-{
- return decNumberIsZero(fDecNumber);
-}
-
-// -------------------------------------
-int32_t
-DigitList::getUpperExponent() const {
- return fDecNumber->digits + fDecNumber->exponent;
-}
-
-DigitInterval &
-DigitList::getSmallestInterval(DigitInterval &result) const {
- result.setLeastSignificantInclusive(fDecNumber->exponent);
- result.setMostSignificantExclusive(getUpperExponent());
- return result;
-}
-
-uint8_t
-DigitList::getDigitByExponent(int32_t exponent) const {
- int32_t idx = exponent - fDecNumber->exponent;
- if (idx < 0 || idx >= fDecNumber->digits) {
- return 0;
- }
- return fDecNumber->lsu[idx];
-}
-
-void
-DigitList::appendDigitsTo(CharString &str, UErrorCode &status) const {
- str.append((const char *) fDecNumber->lsu, fDecNumber->digits, status);
-}
-
-void
-DigitList::roundAtExponent(int32_t exponent, int32_t maxSigDigits) {
- reduce();
- if (maxSigDigits < fDecNumber->digits) {
- int32_t minExponent = getUpperExponent() - maxSigDigits;
- if (exponent < minExponent) {
- exponent = minExponent;
- }
- }
- if (exponent <= fDecNumber->exponent) {
- return;
- }
- int32_t digits = getUpperExponent() - exponent;
- if (digits > 0) {
- round(digits);
- } else {
- roundFixedPoint(-exponent);
- }
-}
-
-void
-DigitList::quantize(const DigitList &quantity, UErrorCode &status) {
- if (U_FAILURE(status)) {
- return;
- }
- div(quantity, status);
- roundAtExponent(0);
- mult(quantity, status);
- reduce();
-}
-
-int32_t
-DigitList::getScientificExponent(
- int32_t minIntDigitCount, int32_t exponentMultiplier) const {
- // The exponent for zero is always zero.
- if (isZero()) {
- return 0;
- }
- int32_t intDigitCount = getUpperExponent();
- int32_t exponent;
- if (intDigitCount >= minIntDigitCount) {
- int32_t maxAdjustment = intDigitCount - minIntDigitCount;
- exponent = (maxAdjustment / exponentMultiplier) * exponentMultiplier;
- } else {
- int32_t minAdjustment = minIntDigitCount - intDigitCount;
- exponent = ((minAdjustment + exponentMultiplier - 1) / exponentMultiplier) * -exponentMultiplier;
- }
- return exponent;
-}
-
-int32_t
-DigitList::toScientific(
- int32_t minIntDigitCount, int32_t exponentMultiplier) {
- int32_t exponent = getScientificExponent(
- minIntDigitCount, exponentMultiplier);
- shiftDecimalRight(-exponent);
- return exponent;
-}
-
-void
-DigitList::shiftDecimalRight(int32_t n) {
- fDecNumber->exponent += n;
- internalClear();
-}
-
-U_NAMESPACE_END
-#endif // #if !UCONFIG_NO_FORMATTING
-
-//eof
diff --git a/deps/icu-small/source/i18n/digitlst.h b/deps/icu-small/source/i18n/digitlst.h
deleted file mode 100644
index 6befaf32e6f340..00000000000000
--- a/deps/icu-small/source/i18n/digitlst.h
+++ /dev/null
@@ -1,529 +0,0 @@
-// © 2016 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html
-/*
-******************************************************************************
-*
-* Copyright (C) 1997-2015, International Business Machines
-* Corporation and others. All Rights Reserved.
-*
-******************************************************************************
-*
-* File DIGITLST.H
-*
-* Modification History:
-*
-* Date Name Description
-* 02/25/97 aliu Converted from java.
-* 03/21/97 clhuang Updated per C++ implementation.
-* 04/15/97 aliu Changed MAX_COUNT to DBL_DIG. Changed Digit to char.
-* 09/09/97 aliu Adapted for exponential notation support.
-* 08/02/98 stephen Added nearest/even rounding
-* 06/29/99 stephen Made LONG_DIGITS a macro to satisfy SUN compiler
-* 07/09/99 stephen Removed kMaxCount (unused, for HP compiler)
-******************************************************************************
-*/
-
-#ifndef DIGITLST_H
-#define DIGITLST_H
-
-#include "unicode/uobject.h"
-
-#if !UCONFIG_NO_FORMATTING
-#include "unicode/decimfmt.h"
-#include
-#include "decContext.h"
-#include "decNumber.h"
-#include "cmemory.h"
-
-// Decimal digits in a 64-bit int
-#define INT64_DIGITS 19
-
-typedef enum EDigitListValues {
- MAX_DBL_DIGITS = DBL_DIG,
- MAX_I64_DIGITS = INT64_DIGITS,
- MAX_DIGITS = MAX_I64_DIGITS,
- MAX_EXPONENT = DBL_DIG,
- DIGIT_PADDING = 3,
- DEFAULT_DIGITS = 40, // Initial storage size, will grow as needed.
-
- // "+." + fDigits + "e" + fDecimalAt
- MAX_DEC_DIGITS = MAX_DIGITS + DIGIT_PADDING + MAX_EXPONENT
-} EDigitListValues;
-
-U_NAMESPACE_BEGIN
-
-class CharString;
-class DigitInterval;
-
-// Export an explicit template instantiation of the MaybeStackHeaderAndArray that
-// is used as a data member of DigitList.
-//
-// MSVC requires this, even though it should not be necessary.
-// No direct access to the MaybeStackHeaderAndArray leaks out of the i18n library.
-//
-// Macintosh produces duplicate definition linker errors with the explicit template
-// instantiation.
-//
-#if !U_PLATFORM_IS_DARWIN_BASED
-template class U_I18N_API MaybeStackHeaderAndArray;
-#endif
-
-
-enum EStackMode { kOnStack };
-
-enum EFastpathBits { kFastpathOk = 1, kNoDecimal = 2 };
-
-/**
- * Digit List is actually a Decimal Floating Point number.
- * The original implementation has been replaced by a thin wrapper onto a
- * decimal number from the decNumber library.
- *
- * The original DigitList API has been retained, to minimize the impact of
- * the change on the rest of the ICU formatting code.
- *
- * The change to decNumber enables support for big decimal numbers, and
- * allows rounding computations to be done directly in decimal, avoiding
- * extra, and inaccurate, conversions to and from doubles.
- *
- * Original DigitList comments:
- *
- * Digit List utility class. Private to DecimalFormat. Handles the transcoding
- * between numeric values and strings of characters. Only handles
- * non-negative numbers. The division of labor between DigitList and
- * DecimalFormat is that DigitList handles the radix 10 representation
- * issues; DecimalFormat handles the locale-specific issues such as
- * positive/negative, grouping, decimal point, currency, and so on.
- *
- * A DigitList is really a representation of a floating point value.
- * It may be an integer value; we assume that a double has sufficient
- * precision to represent all digits of a long.
- *
- * The DigitList representation consists of a string of characters,
- * which are the digits radix 10, from '0' to '9'. It also has a radix
- * 10 exponent associated with it. The value represented by a DigitList
- * object can be computed by mulitplying the fraction f, where 0 <= f < 1,
- * derived by placing all the digits of the list to the right of the
- * decimal point, by 10^exponent.
- *
- * --------
- *
- * DigitList vs. decimalNumber:
- *
- * DigitList stores digits with the most significant first.
- * decNumber stores digits with the least significant first.
- *
- * DigitList, decimal point is before the most significant.
- * decNumber, decimal point is after the least signficant digit.
- *
- * digitList: 0.ddddd * 10 ^ exp
- * decNumber: ddddd. * 10 ^ exp
- *
- * digitList exponent = decNumber exponent + digit count
- *
- * digitList, digits are platform invariant chars, '0' - '9'
- * decNumber, digits are binary, one per byte, 0 - 9.
- *
- * (decNumber library is configurable in how digits are stored, ICU has configured
- * it this way for convenience in replacing the old DigitList implementation.)
- */
-class U_I18N_API DigitList : public UMemory { // Declare external to make compiler happy
-public:
-
- DigitList();
- ~DigitList();
-
- /* copy constructor
- * @param DigitList The object to be copied.
- * @return the newly created object.
- */
- DigitList(const DigitList&); // copy constructor
-
- /* assignment operator
- * @param DigitList The object to be copied.
- * @return the newly created object.
- */
- DigitList& operator=(const DigitList&); // assignment operator
-
- /**
- * Return true if another object is semantically equal to this one.
- * @param other The DigitList to be compared for equality
- * @return true if another object is semantically equal to this one.
- * return false otherwise.
- */
- UBool operator==(const DigitList& other) const;
-
- int32_t compare(const DigitList& other);
-
-
- inline UBool operator!=(const DigitList& other) const { return !operator==(other); }
-
- /**
- * Clears out the digits.
- * Use before appending them.
- * Typically, you set a series of digits with append, then at the point
- * you hit the decimal point, you set myDigitList.fDecimalAt = myDigitList.fCount;
- * then go on appending digits.
- */
- void clear(void);
-
- /**
- * Remove, by rounding, any fractional part of the decimal number,
- * leaving an integer value.
- */
- void toIntegralValue();
-
- /**
- * Appends digits to the list.
- * CAUTION: this function is not recommended for new code.
- * In the original DigitList implementation, decimal numbers were
- * parsed by appending them to a digit list as they were encountered.
- * With the revamped DigitList based on decNumber, append is very
- * inefficient, and the interaction with the exponent value is confusing.
- * Best avoided.
- * TODO: remove this function once all use has been replaced.
- * TODO: describe alternative to append()
- * @param digit The digit to be appended.
- */
- void append(char digit);
-
- /**
- * Utility routine to get the value of the digit list
- * Returns 0.0 if zero length.
- * @return the value of the digit list.
- */
- double getDouble(void) const;
-
- /**
- * Utility routine to get the value of the digit list
- * Make sure that fitsIntoLong() is called before calling this function.
- * Returns 0 if zero length.
- * @return the value of the digit list, return 0 if it is zero length
- */
- int32_t getLong(void) /*const*/;
-
- /**
- * Utility routine to get the value of the digit list
- * Make sure that fitsIntoInt64() is called before calling this function.
- * Returns 0 if zero length.
- * @return the value of the digit list, return 0 if it is zero length
- */
- int64_t getInt64(void) /*const*/;
-
- /**
- * Utility routine to get the value of the digit list as a decimal string.
- */
- void getDecimal(CharString &str, UErrorCode &status);
-
- /**
- * Return true if the number represented by this object can fit into
- * a long.
- * @param ignoreNegativeZero True if negative zero is ignored.
- * @return true if the number represented by this object can fit into
- * a long, return false otherwise.
- */
- UBool fitsIntoLong(UBool ignoreNegativeZero) /*const*/;
-
- /**
- * Return true if the number represented by this object can fit into
- * an int64_t.
- * @param ignoreNegativeZero True if negative zero is ignored.
- * @return true if the number represented by this object can fit into
- * a long, return false otherwise.
- */
- UBool fitsIntoInt64(UBool ignoreNegativeZero) /*const*/;
-
- /**
- * Utility routine to set the value of the digit list from a double.
- * @param source The value to be set
- */
- void set(double source);
-
- /**
- * Utility routine to set the value of the digit list from a long.
- * If a non-zero maximumDigits is specified, no more than that number of
- * significant digits will be produced.
- * @param source The value to be set
- */
- void set(int32_t source);
-
- /**
- * Utility routine to set the value of the digit list from an int64.
- * If a non-zero maximumDigits is specified, no more than that number of
- * significant digits will be produced.
- * @param source The value to be set
- */
- void set(int64_t source);
-
- /**
- * Utility routine to set the value of the digit list from an int64.
- * Does not set the decnumber unless requested later
- * If a non-zero maximumDigits is specified, no more than that number of
- * significant digits will be produced.
- * @param source The value to be set
- */
- void setInteger(int64_t source);
-
- /**
- * Utility routine to set the value of the digit list from a decimal number
- * string.
- * @param source The value to be set. The string must be nul-terminated.
- * @param fastpathBits special flags for fast parsing
- */
- void set(StringPiece source, UErrorCode &status, uint32_t fastpathBits = 0);
-
- /**
- * Multiply this = this * arg
- * This digitlist will be expanded if necessary to accomodate the result.
- * @param arg the number to multiply by.
- */
- void mult(const DigitList &arg, UErrorCode &status);
-
- /**
- * Divide this = this / arg
- */
- void div(const DigitList &arg, UErrorCode &status);
-
- // The following functions replace direct access to the original DigitList implmentation
- // data structures.
-
- void setRoundingMode(DecimalFormat::ERoundingMode m);
-
- /** Test a number for zero.
- * @return TRUE if the number is zero
- */
- UBool isZero(void) const;
-
- /** Test for a Nan
- * @return TRUE if the number is a NaN
- */
- UBool isNaN(void) const {return decNumberIsNaN(fDecNumber);}
-
- UBool isInfinite() const {return decNumberIsInfinite(fDecNumber);}
-
- /** Reduce, or normalize. Removes trailing zeroes, adjusts exponent appropriately. */
- void reduce();
-
- /** Remove trailing fraction zeros, adjust exponent accordingly. */
- void trim();
-
- /** Set to zero */
- void setToZero() {uprv_decNumberZero(fDecNumber);}
-
- /** get the number of digits in the decimal number */
- int32_t digits() const {return fDecNumber->digits;}
-
- /**
- * Round the number to the given number of digits.
- * @param maximumDigits The maximum number of digits to be shown.
- * Upon return, count will be less than or equal to maximumDigits.
- * result is guaranteed to be trimmed.
- */
- void round(int32_t maximumDigits);
-
- void roundFixedPoint(int32_t maximumFractionDigits);
-
- /** Ensure capacity for digits. Grow the storage if it is currently less than
- * the requested size. Capacity is not reduced if it is already greater
- * than requested.
- */
- void ensureCapacity(int32_t requestedSize, UErrorCode &status);
-
- UBool isPositive(void) const { return decNumberIsNegative(fDecNumber) == 0;}
- void setPositive(UBool s);
-
- void setDecimalAt(int32_t d);
- int32_t getDecimalAt();
-
- void setCount(int32_t c);
- int32_t getCount() const;
-
- /**
- * Set the digit in platform (invariant) format, from '0'..'9'
- * @param i index of digit
- * @param v digit value, from '0' to '9' in platform invariant format
- */
- void setDigit(int32_t i, char v);
-
- /**
- * Get the digit in platform (invariant) format, from '0'..'9' inclusive
- * @param i index of digit
- * @return invariant format of the digit
- */
- char getDigit(int32_t i);
-
-
- /**
- * Get the digit's value, as an integer from 0..9 inclusive.
- * Note that internally this value is a decNumberUnit, but ICU configures it to be a uint8_t.
- * @param i index of digit
- * @return value of that digit
- */
- uint8_t getDigitValue(int32_t i);
-
- /**
- * Gets the upper bound exponent for this value. For 987, returns 3
- * because 10^3 is the smallest power of 10 that is just greater than
- * 987.
- */
- int32_t getUpperExponent() const;
-
- /**
- * Gets the lower bound exponent for this value. For 98.7, returns -1
- * because the right most digit, is the 10^-1 place.
- */
- int32_t getLowerExponent() const { return fDecNumber->exponent; }
-
- /**
- * Sets result to the smallest DigitInterval needed to display this
- * DigitList in fixed point form and returns result.
- */
- DigitInterval& getSmallestInterval(DigitInterval &result) const;
-
- /**
- * Like getDigitValue, but the digit is identified by exponent.
- * For example, getDigitByExponent(7) returns the 10^7 place of this
- * DigitList. Unlike getDigitValue, there are no upper or lower bounds
- * for passed parameter. Instead, getDigitByExponent returns 0 if
- * the exponent falls outside the interval for this DigitList.
- */
- uint8_t getDigitByExponent(int32_t exponent) const;
-
- /**
- * Appends the digits in this object to a CharString.
- * 3 is appended as (char) 3, not '3'
- */
- void appendDigitsTo(CharString &str, UErrorCode &status) const;
-
- /**
- * Equivalent to roundFixedPoint(-digitExponent) except unlike
- * roundFixedPoint, this works for any digitExponent value.
- * If maxSigDigits is set then this instance is rounded to have no more
- * than maxSigDigits. The end result is guaranteed to be trimmed.
- */
- void roundAtExponent(int32_t digitExponent, int32_t maxSigDigits=INT32_MAX);
-
- /**
- * Quantizes according to some amount and rounds according to the
- * context of this instance. Quantizing 3.233 with 0.05 gives 3.25.
- */
- void quantize(const DigitList &amount, UErrorCode &status);
-
- /**
- * Like toScientific but only returns the exponent
- * leaving this instance unchanged.
- */
- int32_t getScientificExponent(
- int32_t minIntDigitCount, int32_t exponentMultiplier) const;
-
- /**
- * Converts this instance to scientific notation. This instance
- * becomes the mantissa and the exponent is returned.
- * @param minIntDigitCount minimum integer digits in mantissa
- * Exponent is set so that the actual number of integer digits
- * in mantissa is as close to the minimum as possible.
- * @param exponentMultiplier The exponent is always a multiple of
- * This number. Usually 1, but set to 3 for engineering notation.
- * @return exponent
- */
- int32_t toScientific(
- int32_t minIntDigitCount, int32_t exponentMultiplier);
-
- /**
- * Shifts decimal to the right.
- */
- void shiftDecimalRight(int32_t numPlaces);
-
-private:
- /*
- * These data members are intentionally public and can be set directly.
- *
- * The value represented is given by placing the decimal point before
- * fDigits[fDecimalAt]. If fDecimalAt is < 0, then leading zeros between
- * the decimal point and the first nonzero digit are implied. If fDecimalAt
- * is > fCount, then trailing zeros between the fDigits[fCount-1] and the
- * decimal point are implied.
- *
- * Equivalently, the represented value is given by f * 10^fDecimalAt. Here
- * f is a value 0.1 <= f < 1 arrived at by placing the digits in fDigits to
- * the right of the decimal.
- *
- * DigitList is normalized, so if it is non-zero, fDigits[0] is non-zero. We
- * don't allow denormalized numbers because our exponent is effectively of
- * unlimited magnitude. The fCount value contains the number of significant
- * digits present in fDigits[].
- *
- * Zero is represented by any DigitList with fCount == 0 or with each fDigits[i]
- * for all i <= fCount == '0'.
- *
- * int32_t fDecimalAt;
- * int32_t fCount;
- * UBool fIsPositive;
- * char *fDigits;
- * DecimalFormat::ERoundingMode fRoundingMode;
- */
-
-public:
- decContext fContext; // public access to status flags.
-
-private:
- decNumber *fDecNumber;
- MaybeStackHeaderAndArray fStorage;
-
- /* Cached double value corresponding to this decimal number.
- * This is an optimization for the formatting implementation, which may
- * ask for the double value multiple times.
- */
- union DoubleOrInt64 {
- double fDouble;
- int64_t fInt64;
- } fUnion;
- enum EHave {
- kNone=0,
- kDouble
- } fHave;
-
-
-
- UBool shouldRoundUp(int32_t maximumDigits) const;
-
- public:
-
-#if U_OVERRIDE_CXX_ALLOCATION
- using UMemory::operator new;
- using UMemory::operator delete;
-#else
- static inline void * U_EXPORT2 operator new(size_t size) U_NO_THROW { return ::operator new(size); };
- static inline void U_EXPORT2 operator delete(void *ptr ) U_NO_THROW { ::operator delete(ptr); };
-#endif
-
- static double U_EXPORT2 decimalStrToDouble(char *decstr, char **end);
-
- /**
- * Placement new for stack usage
- * @internal
- */
- static inline void * U_EXPORT2 operator new(size_t /*size*/, void * onStack, EStackMode /*mode*/) U_NO_THROW { return onStack; }
-
- /**
- * Placement delete for stack usage
- * @internal
- */
- static inline void U_EXPORT2 operator delete(void * /*ptr*/, void * /*onStack*/, EStackMode /*mode*/) U_NO_THROW {}
-
- private:
- inline void internalSetDouble(double d) {
- fHave = kDouble;
- fUnion.fDouble=d;
- }
- inline void internalClear() {
- fHave = kNone;
- }
-};
-
-
-U_NAMESPACE_END
-
-#endif // #if !UCONFIG_NO_FORMATTING
-#endif // _DIGITLST
-
-//eof
diff --git a/deps/icu-small/source/i18n/double-conversion-strtod.cpp b/deps/icu-small/source/i18n/double-conversion-strtod.cpp
new file mode 100644
index 00000000000000..be9b0b3bce0e76
--- /dev/null
+++ b/deps/icu-small/source/i18n/double-conversion-strtod.cpp
@@ -0,0 +1,574 @@
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+//
+// From the double-conversion library. Original license:
+//
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ICU PATCH: ifdef around UCONFIG_NO_FORMATTING
+#include "unicode/utypes.h"
+#if !UCONFIG_NO_FORMATTING
+
+#include
+#include
+
+// ICU PATCH: Customize header file paths for ICU.
+// The file fixed-dtoa.h is not needed.
+
+#include "double-conversion-strtod.h"
+#include "double-conversion-bignum.h"
+#include "double-conversion-cached-powers.h"
+#include "double-conversion-ieee.h"
+
+// ICU PATCH: Wrap in ICU namespace
+U_NAMESPACE_BEGIN
+
+namespace double_conversion {
+
+// 2^53 = 9007199254740992.
+// Any integer with at most 15 decimal digits will hence fit into a double
+// (which has a 53bit significand) without loss of precision.
+static const int kMaxExactDoubleIntegerDecimalDigits = 15;
+// 2^64 = 18446744073709551616 > 10^19
+static const int kMaxUint64DecimalDigits = 19;
+
+// Max double: 1.7976931348623157 x 10^308
+// Min non-zero double: 4.9406564584124654 x 10^-324
+// Any x >= 10^309 is interpreted as +infinity.
+// Any x <= 10^-324 is interpreted as 0.
+// Note that 2.5e-324 (despite being smaller than the min double) will be read
+// as non-zero (equal to the min non-zero double).
+static const int kMaxDecimalPower = 309;
+static const int kMinDecimalPower = -324;
+
+// 2^64 = 18446744073709551616
+static const uint64_t kMaxUint64 = UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF);
+
+
+static const double exact_powers_of_ten[] = {
+ 1.0, // 10^0
+ 10.0,
+ 100.0,
+ 1000.0,
+ 10000.0,
+ 100000.0,
+ 1000000.0,
+ 10000000.0,
+ 100000000.0,
+ 1000000000.0,
+ 10000000000.0, // 10^10
+ 100000000000.0,
+ 1000000000000.0,
+ 10000000000000.0,
+ 100000000000000.0,
+ 1000000000000000.0,
+ 10000000000000000.0,
+ 100000000000000000.0,
+ 1000000000000000000.0,
+ 10000000000000000000.0,
+ 100000000000000000000.0, // 10^20
+ 1000000000000000000000.0,
+ // 10^22 = 0x21e19e0c9bab2400000 = 0x878678326eac9 * 2^22
+ 10000000000000000000000.0
+};
+static const int kExactPowersOfTenSize = ARRAY_SIZE(exact_powers_of_ten);
+
+// Maximum number of significant digits in the decimal representation.
+// In fact the value is 772 (see conversions.cc), but to give us some margin
+// we round up to 780.
+static const int kMaxSignificantDecimalDigits = 780;
+
+static Vector TrimLeadingZeros(Vector buffer) {
+ for (int i = 0; i < buffer.length(); i++) {
+ if (buffer[i] != '0') {
+ return buffer.SubVector(i, buffer.length());
+ }
+ }
+ return Vector(buffer.start(), 0);
+}
+
+
+static Vector TrimTrailingZeros(Vector buffer) {
+ for (int i = buffer.length() - 1; i >= 0; --i) {
+ if (buffer[i] != '0') {
+ return buffer.SubVector(0, i + 1);
+ }
+ }
+ return Vector(buffer.start(), 0);
+}
+
+
+static void CutToMaxSignificantDigits(Vector buffer,
+ int exponent,
+ char* significant_buffer,
+ int* significant_exponent) {
+ for (int i = 0; i < kMaxSignificantDecimalDigits - 1; ++i) {
+ significant_buffer[i] = buffer[i];
+ }
+ // The input buffer has been trimmed. Therefore the last digit must be
+ // different from '0'.
+ ASSERT(buffer[buffer.length() - 1] != '0');
+ // Set the last digit to be non-zero. This is sufficient to guarantee
+ // correct rounding.
+ significant_buffer[kMaxSignificantDecimalDigits - 1] = '1';
+ *significant_exponent =
+ exponent + (buffer.length() - kMaxSignificantDecimalDigits);
+}
+
+
+// Trims the buffer and cuts it to at most kMaxSignificantDecimalDigits.
+// If possible the input-buffer is reused, but if the buffer needs to be
+// modified (due to cutting), then the input needs to be copied into the
+// buffer_copy_space.
+static void TrimAndCut(Vector buffer, int exponent,
+ char* buffer_copy_space, int space_size,
+ Vector* trimmed, int* updated_exponent) {
+ Vector left_trimmed = TrimLeadingZeros(buffer);
+ Vector right_trimmed = TrimTrailingZeros(left_trimmed);
+ exponent += left_trimmed.length() - right_trimmed.length();
+ if (right_trimmed.length() > kMaxSignificantDecimalDigits) {
+ (void) space_size; // Mark variable as used.
+ ASSERT(space_size >= kMaxSignificantDecimalDigits);
+ CutToMaxSignificantDigits(right_trimmed, exponent,
+ buffer_copy_space, updated_exponent);
+ *trimmed = Vector(buffer_copy_space,
+ kMaxSignificantDecimalDigits);
+ } else {
+ *trimmed = right_trimmed;
+ *updated_exponent = exponent;
+ }
+}
+
+
+// Reads digits from the buffer and converts them to a uint64.
+// Reads in as many digits as fit into a uint64.
+// When the string starts with "1844674407370955161" no further digit is read.
+// Since 2^64 = 18446744073709551616 it would still be possible read another
+// digit if it was less or equal than 6, but this would complicate the code.
+static uint64_t ReadUint64(Vector buffer,
+ int* number_of_read_digits) {
+ uint64_t result = 0;
+ int i = 0;
+ while (i < buffer.length() && result <= (kMaxUint64 / 10 - 1)) {
+ int digit = buffer[i++] - '0';
+ ASSERT(0 <= digit && digit <= 9);
+ result = 10 * result + digit;
+ }
+ *number_of_read_digits = i;
+ return result;
+}
+
+
+// Reads a DiyFp from the buffer.
+// The returned DiyFp is not necessarily normalized.
+// If remaining_decimals is zero then the returned DiyFp is accurate.
+// Otherwise it has been rounded and has error of at most 1/2 ulp.
+static void ReadDiyFp(Vector buffer,
+ DiyFp* result,
+ int* remaining_decimals) {
+ int read_digits;
+ uint64_t significand = ReadUint64(buffer, &read_digits);
+ if (buffer.length() == read_digits) {
+ *result = DiyFp(significand, 0);
+ *remaining_decimals = 0;
+ } else {
+ // Round the significand.
+ if (buffer[read_digits] >= '5') {
+ significand++;
+ }
+ // Compute the binary exponent.
+ int exponent = 0;
+ *result = DiyFp(significand, exponent);
+ *remaining_decimals = buffer.length() - read_digits;
+ }
+}
+
+
+static bool DoubleStrtod(Vector trimmed,
+ int exponent,
+ double* result) {
+#if !defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS)
+ // On x86 the floating-point stack can be 64 or 80 bits wide. If it is
+ // 80 bits wide (as is the case on Linux) then double-rounding occurs and the
+ // result is not accurate.
+ // We know that Windows32 uses 64 bits and is therefore accurate.
+ // Note that the ARM simulator is compiled for 32bits. It therefore exhibits
+ // the same problem.
+ return false;
+#endif
+ if (trimmed.length() <= kMaxExactDoubleIntegerDecimalDigits) {
+ int read_digits;
+ // The trimmed input fits into a double.
+ // If the 10^exponent (resp. 10^-exponent) fits into a double too then we
+ // can compute the result-double simply by multiplying (resp. dividing) the
+ // two numbers.
+ // This is possible because IEEE guarantees that floating-point operations
+ // return the best possible approximation.
+ if (exponent < 0 && -exponent < kExactPowersOfTenSize) {
+ // 10^-exponent fits into a double.
+ *result = static_cast(ReadUint64(trimmed, &read_digits));
+ ASSERT(read_digits == trimmed.length());
+ *result /= exact_powers_of_ten[-exponent];
+ return true;
+ }
+ if (0 <= exponent && exponent < kExactPowersOfTenSize) {
+ // 10^exponent fits into a double.
+ *result = static_cast(ReadUint64(trimmed, &read_digits));
+ ASSERT(read_digits == trimmed.length());
+ *result *= exact_powers_of_ten[exponent];
+ return true;
+ }
+ int remaining_digits =
+ kMaxExactDoubleIntegerDecimalDigits - trimmed.length();
+ if ((0 <= exponent) &&
+ (exponent - remaining_digits < kExactPowersOfTenSize)) {
+ // The trimmed string was short and we can multiply it with
+ // 10^remaining_digits. As a result the remaining exponent now fits
+ // into a double too.
+ *result = static_cast(ReadUint64(trimmed, &read_digits));
+ ASSERT(read_digits == trimmed.length());
+ *result *= exact_powers_of_ten[remaining_digits];
+ *result *= exact_powers_of_ten[exponent - remaining_digits];
+ return true;
+ }
+ }
+ return false;
+}
+
+
+// Returns 10^exponent as an exact DiyFp.
+// The given exponent must be in the range [1; kDecimalExponentDistance[.
+static DiyFp AdjustmentPowerOfTen(int exponent) {
+ ASSERT(0 < exponent);
+ ASSERT(exponent < PowersOfTenCache::kDecimalExponentDistance);
+ // Simply hardcode the remaining powers for the given decimal exponent
+ // distance.
+ ASSERT(PowersOfTenCache::kDecimalExponentDistance == 8);
+ switch (exponent) {
+ case 1: return DiyFp(UINT64_2PART_C(0xa0000000, 00000000), -60);
+ case 2: return DiyFp(UINT64_2PART_C(0xc8000000, 00000000), -57);
+ case 3: return DiyFp(UINT64_2PART_C(0xfa000000, 00000000), -54);
+ case 4: return DiyFp(UINT64_2PART_C(0x9c400000, 00000000), -50);
+ case 5: return DiyFp(UINT64_2PART_C(0xc3500000, 00000000), -47);
+ case 6: return DiyFp(UINT64_2PART_C(0xf4240000, 00000000), -44);
+ case 7: return DiyFp(UINT64_2PART_C(0x98968000, 00000000), -40);
+ default:
+ UNREACHABLE();
+ }
+}
+
+
+// If the function returns true then the result is the correct double.
+// Otherwise it is either the correct double or the double that is just below
+// the correct double.
+static bool DiyFpStrtod(Vector buffer,
+ int exponent,
+ double* result) {
+ DiyFp input;
+ int remaining_decimals;
+ ReadDiyFp(buffer, &input, &remaining_decimals);
+ // Since we may have dropped some digits the input is not accurate.
+ // If remaining_decimals is different than 0 than the error is at most
+ // .5 ulp (unit in the last place).
+ // We don't want to deal with fractions and therefore keep a common
+ // denominator.
+ const int kDenominatorLog = 3;
+ const int kDenominator = 1 << kDenominatorLog;
+ // Move the remaining decimals into the exponent.
+ exponent += remaining_decimals;
+ uint64_t error = (remaining_decimals == 0 ? 0 : kDenominator / 2);
+
+ int old_e = input.e();
+ input.Normalize();
+ error <<= old_e - input.e();
+
+ ASSERT(exponent <= PowersOfTenCache::kMaxDecimalExponent);
+ if (exponent < PowersOfTenCache::kMinDecimalExponent) {
+ *result = 0.0;
+ return true;
+ }
+ DiyFp cached_power;
+ int cached_decimal_exponent;
+ PowersOfTenCache::GetCachedPowerForDecimalExponent(exponent,
+ &cached_power,
+ &cached_decimal_exponent);
+
+ if (cached_decimal_exponent != exponent) {
+ int adjustment_exponent = exponent - cached_decimal_exponent;
+ DiyFp adjustment_power = AdjustmentPowerOfTen(adjustment_exponent);
+ input.Multiply(adjustment_power);
+ if (kMaxUint64DecimalDigits - buffer.length() >= adjustment_exponent) {
+ // The product of input with the adjustment power fits into a 64 bit
+ // integer.
+ ASSERT(DiyFp::kSignificandSize == 64);
+ } else {
+ // The adjustment power is exact. There is hence only an error of 0.5.
+ error += kDenominator / 2;
+ }
+ }
+
+ input.Multiply(cached_power);
+ // The error introduced by a multiplication of a*b equals
+ // error_a + error_b + error_a*error_b/2^64 + 0.5
+ // Substituting a with 'input' and b with 'cached_power' we have
+ // error_b = 0.5 (all cached powers have an error of less than 0.5 ulp),
+ // error_ab = 0 or 1 / kDenominator > error_a*error_b/ 2^64
+ int error_b = kDenominator / 2;
+ int error_ab = (error == 0 ? 0 : 1); // We round up to 1.
+ int fixed_error = kDenominator / 2;
+ error += error_b + error_ab + fixed_error;
+
+ old_e = input.e();
+ input.Normalize();
+ error <<= old_e - input.e();
+
+ // See if the double's significand changes if we add/subtract the error.
+ int order_of_magnitude = DiyFp::kSignificandSize + input.e();
+ int effective_significand_size =
+ Double::SignificandSizeForOrderOfMagnitude(order_of_magnitude);
+ int precision_digits_count =
+ DiyFp::kSignificandSize - effective_significand_size;
+ if (precision_digits_count + kDenominatorLog >= DiyFp::kSignificandSize) {
+ // This can only happen for very small denormals. In this case the
+ // half-way multiplied by the denominator exceeds the range of an uint64.
+ // Simply shift everything to the right.
+ int shift_amount = (precision_digits_count + kDenominatorLog) -
+ DiyFp::kSignificandSize + 1;
+ input.set_f(input.f() >> shift_amount);
+ input.set_e(input.e() + shift_amount);
+ // We add 1 for the lost precision of error, and kDenominator for
+ // the lost precision of input.f().
+ error = (error >> shift_amount) + 1 + kDenominator;
+ precision_digits_count -= shift_amount;
+ }
+ // We use uint64_ts now. This only works if the DiyFp uses uint64_ts too.
+ ASSERT(DiyFp::kSignificandSize == 64);
+ ASSERT(precision_digits_count < 64);
+ uint64_t one64 = 1;
+ uint64_t precision_bits_mask = (one64 << precision_digits_count) - 1;
+ uint64_t precision_bits = input.f() & precision_bits_mask;
+ uint64_t half_way = one64 << (precision_digits_count - 1);
+ precision_bits *= kDenominator;
+ half_way *= kDenominator;
+ DiyFp rounded_input(input.f() >> precision_digits_count,
+ input.e() + precision_digits_count);
+ if (precision_bits >= half_way + error) {
+ rounded_input.set_f(rounded_input.f() + 1);
+ }
+ // If the last_bits are too close to the half-way case than we are too
+ // inaccurate and round down. In this case we return false so that we can
+ // fall back to a more precise algorithm.
+
+ *result = Double(rounded_input).value();
+ if (half_way - error < precision_bits && precision_bits < half_way + error) {
+ // Too imprecise. The caller will have to fall back to a slower version.
+ // However the returned number is guaranteed to be either the correct
+ // double, or the next-lower double.
+ return false;
+ } else {
+ return true;
+ }
+}
+
+
+// Returns
+// - -1 if buffer*10^exponent < diy_fp.
+// - 0 if buffer*10^exponent == diy_fp.
+// - +1 if buffer*10^exponent > diy_fp.
+// Preconditions:
+// buffer.length() + exponent <= kMaxDecimalPower + 1
+// buffer.length() + exponent > kMinDecimalPower
+// buffer.length() <= kMaxDecimalSignificantDigits
+static int CompareBufferWithDiyFp(Vector buffer,
+ int exponent,
+ DiyFp diy_fp) {
+ ASSERT(buffer.length() + exponent <= kMaxDecimalPower + 1);
+ ASSERT(buffer.length() + exponent > kMinDecimalPower);
+ ASSERT(buffer.length() <= kMaxSignificantDecimalDigits);
+ // Make sure that the Bignum will be able to hold all our numbers.
+ // Our Bignum implementation has a separate field for exponents. Shifts will
+ // consume at most one bigit (< 64 bits).
+ // ln(10) == 3.3219...
+ ASSERT(((kMaxDecimalPower + 1) * 333 / 100) < Bignum::kMaxSignificantBits);
+ Bignum buffer_bignum;
+ Bignum diy_fp_bignum;
+ buffer_bignum.AssignDecimalString(buffer);
+ diy_fp_bignum.AssignUInt64(diy_fp.f());
+ if (exponent >= 0) {
+ buffer_bignum.MultiplyByPowerOfTen(exponent);
+ } else {
+ diy_fp_bignum.MultiplyByPowerOfTen(-exponent);
+ }
+ if (diy_fp.e() > 0) {
+ diy_fp_bignum.ShiftLeft(diy_fp.e());
+ } else {
+ buffer_bignum.ShiftLeft(-diy_fp.e());
+ }
+ return Bignum::Compare(buffer_bignum, diy_fp_bignum);
+}
+
+
+// Returns true if the guess is the correct double.
+// Returns false, when guess is either correct or the next-lower double.
+static bool ComputeGuess(Vector trimmed, int exponent,
+ double* guess) {
+ if (trimmed.length() == 0) {
+ *guess = 0.0;
+ return true;
+ }
+ if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) {
+ *guess = Double::Infinity();
+ return true;
+ }
+ if (exponent + trimmed.length() <= kMinDecimalPower) {
+ *guess = 0.0;
+ return true;
+ }
+
+ if (DoubleStrtod(trimmed, exponent, guess) ||
+ DiyFpStrtod(trimmed, exponent, guess)) {
+ return true;
+ }
+ if (*guess == Double::Infinity()) {
+ return true;
+ }
+ return false;
+}
+
+double Strtod(Vector buffer, int exponent) {
+ char copy_buffer[kMaxSignificantDecimalDigits];
+ Vector trimmed;
+ int updated_exponent;
+ TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits,
+ &trimmed, &updated_exponent);
+ exponent = updated_exponent;
+
+ double guess;
+ bool is_correct = ComputeGuess(trimmed, exponent, &guess);
+ if (is_correct) return guess;
+
+ DiyFp upper_boundary = Double(guess).UpperBoundary();
+ int comparison = CompareBufferWithDiyFp(trimmed, exponent, upper_boundary);
+ if (comparison < 0) {
+ return guess;
+ } else if (comparison > 0) {
+ return Double(guess).NextDouble();
+ } else if ((Double(guess).Significand() & 1) == 0) {
+ // Round towards even.
+ return guess;
+ } else {
+ return Double(guess).NextDouble();
+ }
+}
+
+float Strtof(Vector buffer, int exponent) {
+ char copy_buffer[kMaxSignificantDecimalDigits];
+ Vector trimmed;
+ int updated_exponent;
+ TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits,
+ &trimmed, &updated_exponent);
+ exponent = updated_exponent;
+
+ double double_guess;
+ bool is_correct = ComputeGuess(trimmed, exponent, &double_guess);
+
+ float float_guess = static_cast(double_guess);
+ if (float_guess == double_guess) {
+ // This shortcut triggers for integer values.
+ return float_guess;
+ }
+
+ // We must catch double-rounding. Say the double has been rounded up, and is
+ // now a boundary of a float, and rounds up again. This is why we have to
+ // look at previous too.
+ // Example (in decimal numbers):
+ // input: 12349
+ // high-precision (4 digits): 1235
+ // low-precision (3 digits):
+ // when read from input: 123
+ // when rounded from high precision: 124.
+ // To do this we simply look at the neigbors of the correct result and see
+ // if they would round to the same float. If the guess is not correct we have
+ // to look at four values (since two different doubles could be the correct
+ // double).
+
+ double double_next = Double(double_guess).NextDouble();
+ double double_previous = Double(double_guess).PreviousDouble();
+
+ float f1 = static_cast(double_previous);
+ float f2 = float_guess;
+ float f3 = static_cast(double_next);
+ float f4;
+ if (is_correct) {
+ f4 = f3;
+ } else {
+ double double_next2 = Double(double_next).NextDouble();
+ f4 = static_cast(double_next2);
+ }
+ (void) f2; // Mark variable as used.
+ ASSERT(f1 <= f2 && f2 <= f3 && f3 <= f4);
+
+ // If the guess doesn't lie near a single-precision boundary we can simply
+ // return its float-value.
+ if (f1 == f4) {
+ return float_guess;
+ }
+
+ ASSERT((f1 != f2 && f2 == f3 && f3 == f4) ||
+ (f1 == f2 && f2 != f3 && f3 == f4) ||
+ (f1 == f2 && f2 == f3 && f3 != f4));
+
+ // guess and next are the two possible canditates (in the same way that
+ // double_guess was the lower candidate for a double-precision guess).
+ float guess = f1;
+ float next = f4;
+ DiyFp upper_boundary;
+ if (guess == 0.0f) {
+ float min_float = 1e-45f;
+ upper_boundary = Double(static_cast(min_float) / 2).AsDiyFp();
+ } else {
+ upper_boundary = Single(guess).UpperBoundary();
+ }
+ int comparison = CompareBufferWithDiyFp(trimmed, exponent, upper_boundary);
+ if (comparison < 0) {
+ return guess;
+ } else if (comparison > 0) {
+ return next;
+ } else if ((Single(guess).Significand() & 1) == 0) {
+ // Round towards even.
+ return guess;
+ } else {
+ return next;
+ }
+}
+
+} // namespace double_conversion
+
+// ICU PATCH: Close ICU namespace
+U_NAMESPACE_END
+#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
diff --git a/deps/icu-small/source/i18n/double-conversion-strtod.h b/deps/icu-small/source/i18n/double-conversion-strtod.h
new file mode 100644
index 00000000000000..e2d6d3c2fe5d7d
--- /dev/null
+++ b/deps/icu-small/source/i18n/double-conversion-strtod.h
@@ -0,0 +1,63 @@
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+//
+// From the double-conversion library. Original license:
+//
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ICU PATCH: ifdef around UCONFIG_NO_FORMATTING
+#include "unicode/utypes.h"
+#if !UCONFIG_NO_FORMATTING
+
+#ifndef DOUBLE_CONVERSION_STRTOD_H_
+#define DOUBLE_CONVERSION_STRTOD_H_
+
+// ICU PATCH: Customize header file paths for ICU.
+
+#include "double-conversion-utils.h"
+
+// ICU PATCH: Wrap in ICU namespace
+U_NAMESPACE_BEGIN
+
+namespace double_conversion {
+
+// The buffer must only contain digits in the range [0-9]. It must not
+// contain a dot or a sign. It must not start with '0', and must not be empty.
+double Strtod(Vector buffer, int exponent);
+
+// The buffer must only contain digits in the range [0-9]. It must not
+// contain a dot or a sign. It must not start with '0', and must not be empty.
+float Strtof(Vector buffer, int exponent);
+
+} // namespace double_conversion
+
+// ICU PATCH: Close ICU namespace
+U_NAMESPACE_END
+
+#endif // DOUBLE_CONVERSION_STRTOD_H_
+#endif // ICU PATCH: close #if !UCONFIG_NO_FORMATTING
diff --git a/deps/icu-small/source/i18n/double-conversion-utils.h b/deps/icu-small/source/i18n/double-conversion-utils.h
index 02795b4bc565ae..57fc49b231a3a0 100644
--- a/deps/icu-small/source/i18n/double-conversion-utils.h
+++ b/deps/icu-small/source/i18n/double-conversion-utils.h
@@ -75,9 +75,9 @@ inline void abort_noreturn() { abort(); }
// the output of the division with the expected result. (Inlining must be
// disabled.)
// On Linux,x86 89255e-22 != Div_double(89255.0/1e22)
-// ICU PATCH: Enable ARM builds for Windows with 'defined(_M_ARM)'.
+// ICU PATCH: Enable ARM32 & ARM64 builds for Windows with 'defined(_M_ARM) || defined(_M_ARM64)'.
#if defined(_M_X64) || defined(__x86_64__) || \
- defined(__ARMEL__) || defined(__avr32__) || defined(_M_ARM) || \
+ defined(__ARMEL__) || defined(__avr32__) || defined(_M_ARM) || defined(_M_ARM64) || \
defined(__hppa__) || defined(__ia64__) || \
defined(__mips__) || \
defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \
diff --git a/deps/icu-small/source/i18n/double-conversion.cpp b/deps/icu-small/source/i18n/double-conversion.cpp
index 8629284aa0e0f5..570a05bc42946c 100644
--- a/deps/icu-small/source/i18n/double-conversion.cpp
+++ b/deps/icu-small/source/i18n/double-conversion.cpp
@@ -38,13 +38,14 @@
#include
// ICU PATCH: Customize header file paths for ICU.
-// The files fixed-dtoa.h and strtod.h are not needed.
+// The file fixed-dtoa.h is not needed.
#include "double-conversion.h"
#include "double-conversion-bignum-dtoa.h"
#include "double-conversion-fast-dtoa.h"
#include "double-conversion-ieee.h"
+#include "double-conversion-strtod.h"
#include "double-conversion-utils.h"
// ICU PATCH: Wrap in ICU namespace
@@ -431,7 +432,6 @@ void DoubleToStringConverter::DoubleToAscii(double v,
}
-#if 0 // not needed for ICU
// Consumes the given substring from the iterator.
// Returns false, if the substring does not match.
template
@@ -469,6 +469,7 @@ static const uc16 kWhitespaceTable16[] = {
static const int kWhitespaceTable16Length = ARRAY_SIZE(kWhitespaceTable16);
+
static bool isWhitespace(int x) {
if (x < 128) {
for (int i = 0; i < kWhitespaceTable7Length; i++) {
@@ -647,7 +648,6 @@ static double RadixStringToIeee(Iterator* current,
return Double(DiyFp(number, exponent)).value();
}
-
template
double StringToDoubleConverter::StringToIeee(
Iterator input,
@@ -996,7 +996,6 @@ float StringToDoubleConverter::StringToFloat(
return static_cast(StringToIeee(buffer, length, false,
processed_characters_count));
}
-#endif // not needed for ICU
} // namespace double_conversion
diff --git a/deps/icu-small/source/i18n/double-conversion.h b/deps/icu-small/source/i18n/double-conversion.h
index 0939412734a6bb..200537a360a7cc 100644
--- a/deps/icu-small/source/i18n/double-conversion.h
+++ b/deps/icu-small/source/i18n/double-conversion.h
@@ -391,6 +391,7 @@ class DoubleToStringConverter {
const int decimal_in_shortest_high_;
const int max_leading_padding_zeroes_in_precision_mode_;
const int max_trailing_padding_zeroes_in_precision_mode_;
+#endif // not needed for ICU
DISALLOW_IMPLICIT_CONSTRUCTORS(DoubleToStringConverter);
};
@@ -554,7 +555,6 @@ class StringToDoubleConverter {
int* processed_characters_count) const;
DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter);
-#endif // not needed for ICU
};
} // namespace double_conversion
diff --git a/deps/icu-small/source/i18n/fmtable.cpp b/deps/icu-small/source/i18n/fmtable.cpp
index 73f9b66ab6f950..cb6134cb4b2423 100644
--- a/deps/icu-small/source/i18n/fmtable.cpp
+++ b/deps/icu-small/source/i18n/fmtable.cpp
@@ -19,6 +19,7 @@
#if !UCONFIG_NO_FORMATTING
+#include
#include
#include "unicode/fmtable.h"
#include "unicode/ustring.h"
@@ -28,9 +29,8 @@
#include "charstr.h"
#include "cmemory.h"
#include "cstring.h"
-#include "decNumber.h"
-#include "digitlst.h"
#include "fmtableimp.h"
+#include "number_decimalquantity.h"
// *****************************************************************************
// class Formattable
@@ -40,6 +40,8 @@ U_NAMESPACE_BEGIN
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Formattable)
+using number::impl::DecimalQuantity;
+
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
@@ -103,7 +105,7 @@ void Formattable::init() {
fValue.fInt64 = 0;
fType = kLong;
fDecimalStr = NULL;
- fDecimalNum = NULL;
+ fDecimalQuantity = NULL;
fBogus.setToBogus();
}
@@ -257,8 +259,8 @@ Formattable::operator=(const Formattable& source)
}
UErrorCode status = U_ZERO_ERROR;
- if (source.fDecimalNum != NULL) {
- fDecimalNum = new DigitList(*source.fDecimalNum); // TODO: use internal digit list
+ if (source.fDecimalQuantity != NULL) {
+ fDecimalQuantity = new DecimalQuantity(*source.fDecimalQuantity);
}
if (source.fDecimalStr != NULL) {
fDecimalStr = new CharString(*source.fDecimalStr, status);
@@ -357,13 +359,8 @@ void Formattable::dispose()
delete fDecimalStr;
fDecimalStr = NULL;
- FmtStackData *stackData = (FmtStackData*)fStackData;
- if(fDecimalNum != &(stackData->stackDecimalNum)) {
- delete fDecimalNum;
- } else {
- fDecimalNum->~DigitList(); // destruct, don't deallocate
- }
- fDecimalNum = NULL;
+ delete fDecimalQuantity;
+ fDecimalQuantity = NULL;
}
Formattable *
@@ -465,13 +462,13 @@ Formattable::getInt64(UErrorCode& status) const
} else if (fValue.fDouble < (double)U_INT64_MIN) {
status = U_INVALID_FORMAT_ERROR;
return U_INT64_MIN;
- } else if (fabs(fValue.fDouble) > U_DOUBLE_MAX_EXACT_INT && fDecimalNum != NULL) {
- int64_t val = fDecimalNum->getInt64();
- if (val != 0) {
- return val;
+ } else if (fabs(fValue.fDouble) > U_DOUBLE_MAX_EXACT_INT && fDecimalQuantity != NULL) {
+ if (fDecimalQuantity->fitsInLong(true)) {
+ return fDecimalQuantity->toLong();
} else {
+ // Unexpected
status = U_INVALID_FORMAT_ERROR;
- return fValue.fDouble > 0 ? U_INT64_MAX : U_INT64_MIN;
+ return fDecimalQuantity->isNegative() ? U_INT64_MIN : U_INT64_MAX;
}
} else {
return (int64_t)fValue.fDouble;
@@ -714,84 +711,85 @@ StringPiece Formattable::getDecimalNumber(UErrorCode &status) {
CharString *Formattable::internalGetCharString(UErrorCode &status) {
if(fDecimalStr == NULL) {
- if (fDecimalNum == NULL) {
+ if (fDecimalQuantity == NULL) {
// No decimal number for the formattable yet. Which means the value was
// set directly by the user as an int, int64 or double. If the value came
// from parsing, or from the user setting a decimal number, fDecimalNum
// would already be set.
//
- fDecimalNum = new DigitList; // TODO: use internal digit list
- if (fDecimalNum == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
-
- switch (fType) {
- case kDouble:
- fDecimalNum->set(this->getDouble());
- break;
- case kLong:
- fDecimalNum->set(this->getLong());
- break;
- case kInt64:
- fDecimalNum->set(this->getInt64());
- break;
- default:
- // The formattable's value is not a numeric type.
- status = U_INVALID_STATE_ERROR;
- return NULL;
- }
+ LocalPointer dq(new DecimalQuantity(), status);
+ if (U_FAILURE(status)) { return nullptr; }
+ populateDecimalQuantity(*dq, status);
+ if (U_FAILURE(status)) { return nullptr; }
+ fDecimalQuantity = dq.orphan();
}
- fDecimalStr = new CharString;
+ fDecimalStr = new CharString();
if (fDecimalStr == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
- fDecimalNum->getDecimal(*fDecimalStr, status);
+ // Older ICUs called uprv_decNumberToString here, which is not exactly the same as
+ // DecimalQuantity::toScientificString(). The biggest difference is that uprv_decNumberToString does
+ // not print scientific notation for magnitudes greater than -5 and smaller than some amount (+5?).
+ if (fDecimalQuantity->isZero()) {
+ fDecimalStr->append("0", -1, status);
+ } else if (std::abs(fDecimalQuantity->getMagnitude()) < 5) {
+ fDecimalStr->appendInvariantChars(fDecimalQuantity->toPlainString(), status);
+ } else {
+ fDecimalStr->appendInvariantChars(fDecimalQuantity->toScientificString(), status);
+ }
}
return fDecimalStr;
}
+void
+Formattable::populateDecimalQuantity(number::impl::DecimalQuantity& output, UErrorCode& status) const {
+ if (fDecimalQuantity != nullptr) {
+ output = *fDecimalQuantity;
+ return;
+ }
-DigitList *
-Formattable::getInternalDigitList() {
- FmtStackData *stackData = (FmtStackData*)fStackData;
- if(fDecimalNum != &(stackData->stackDecimalNum)) {
- delete fDecimalNum;
- fDecimalNum = new (&(stackData->stackDecimalNum), kOnStack) DigitList();
- } else {
- fDecimalNum->clear();
- }
- return fDecimalNum;
+ switch (fType) {
+ case kDouble:
+ output.setToDouble(this->getDouble());
+ output.roundToInfinity();
+ break;
+ case kLong:
+ output.setToInt(this->getLong());
+ break;
+ case kInt64:
+ output.setToLong(this->getInt64());
+ break;
+ default:
+ // The formattable's value is not a numeric type.
+ status = U_INVALID_STATE_ERROR;
+ }
}
// ---------------------------------------
void
-Formattable::adoptDigitList(DigitList *dl) {
- if(fDecimalNum==dl) {
- fDecimalNum = NULL; // don't delete
- }
- dispose();
-
- fDecimalNum = dl;
-
- if(dl==NULL) { // allow adoptDigitList(NULL) to clear
- return;
- }
+Formattable::adoptDecimalQuantity(DecimalQuantity *dq) {
+ if (fDecimalQuantity != NULL) {
+ delete fDecimalQuantity;
+ }
+ fDecimalQuantity = dq;
+ if (dq == NULL) { // allow adoptDigitList(NULL) to clear
+ return;
+ }
// Set the value into the Union of simple type values.
- // Cannot use the set() functions because they would delete the fDecimalNum value,
-
- if (fDecimalNum->fitsIntoLong(FALSE)) {
- fType = kLong;
- fValue.fInt64 = fDecimalNum->getLong();
- } else if (fDecimalNum->fitsIntoInt64(FALSE)) {
- fType = kInt64;
- fValue.fInt64 = fDecimalNum->getInt64();
+ // Cannot use the set() functions because they would delete the fDecimalNum value.
+ if (fDecimalQuantity->fitsInLong()) {
+ fValue.fInt64 = fDecimalQuantity->toLong();
+ if (fValue.fInt64 <= INT32_MAX && fValue.fInt64 >= INT32_MIN) {
+ fType = kLong;
+ } else {
+ fType = kInt64;
+ }
} else {
fType = kDouble;
- fValue.fDouble = fDecimalNum->getDouble();
+ fValue.fDouble = fDecimalQuantity->toDouble();
}
}
@@ -804,24 +802,12 @@ Formattable::setDecimalNumber(StringPiece numberString, UErrorCode &status) {
}
dispose();
- // Copy the input string and nul-terminate it.
- // The decNumber library requires nul-terminated input. StringPiece input
- // is not guaranteed nul-terminated. Too bad.
- // CharString automatically adds the nul.
- DigitList *dnum = new DigitList(); // TODO: use getInternalDigitList
- if (dnum == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
- }
- dnum->set(CharString(numberString, status).toStringPiece(), status);
- if (U_FAILURE(status)) {
- delete dnum;
- return; // String didn't contain a decimal number.
- }
- adoptDigitList(dnum);
+ auto* dq = new DecimalQuantity();
+ dq->setToDecNumber(numberString, status);
+ adoptDecimalQuantity(dq);
// Note that we do not hang on to the caller's input string.
- // If we are asked for the string, we will regenerate one from fDecimalNum.
+ // If we are asked for the string, we will regenerate one from fDecimalQuantity.
}
#if 0
diff --git a/deps/icu-small/source/i18n/fmtableimp.h b/deps/icu-small/source/i18n/fmtableimp.h
index 0e6ccd24da7f02..78b7caff548e82 100644
--- a/deps/icu-small/source/i18n/fmtableimp.h
+++ b/deps/icu-small/source/i18n/fmtableimp.h
@@ -10,22 +10,12 @@
#ifndef FMTABLEIMP_H
#define FMTABLEIMP_H
-#include "digitlst.h"
+#include "number_decimalquantity.h"
#if !UCONFIG_NO_FORMATTING
U_NAMESPACE_BEGIN
-/**
- * @internal
- */
-struct FmtStackData {
- DigitList stackDecimalNum; // 128
- //CharString stackDecimalStr; // 64
- // -----
- // 192 total
-};
-
/**
* Maximum int64_t value that can be stored in a double without chancing losing precision.
* IEEE doubles have 53 bits of mantissa, 10 bits exponent, 1 bit sign.
diff --git a/deps/icu-small/source/i18n/fphdlimp.cpp b/deps/icu-small/source/i18n/fphdlimp.cpp
index abcec97ee3171c..c4015fae1bbaff 100644
--- a/deps/icu-small/source/i18n/fphdlimp.cpp
+++ b/deps/icu-small/source/i18n/fphdlimp.cpp
@@ -22,17 +22,8 @@ U_NAMESPACE_BEGIN
FieldPositionHandler::~FieldPositionHandler() {
}
-void
-FieldPositionHandler::addAttribute(int32_t, int32_t, int32_t) {
-}
-
-void
-FieldPositionHandler::shiftLast(int32_t) {
-}
-
-UBool
-FieldPositionHandler::isRecording(void) const {
- return FALSE;
+void FieldPositionHandler::setShift(int32_t delta) {
+ fShift = delta;
}
@@ -48,8 +39,8 @@ FieldPositionOnlyHandler::~FieldPositionOnlyHandler() {
void
FieldPositionOnlyHandler::addAttribute(int32_t id, int32_t start, int32_t limit) {
if (pos.getField() == id) {
- pos.setBeginIndex(start);
- pos.setEndIndex(limit);
+ pos.setBeginIndex(start + fShift);
+ pos.setEndIndex(limit + fShift);
}
}
@@ -91,8 +82,8 @@ FieldPositionIteratorHandler::addAttribute(int32_t id, int32_t start, int32_t li
if (iter && U_SUCCESS(status) && start < limit) {
int32_t size = vec->size();
vec->addElement(id, status);
- vec->addElement(start, status);
- vec->addElement(limit, status);
+ vec->addElement(start + fShift, status);
+ vec->addElement(limit + fShift, status);
if (!U_SUCCESS(status)) {
vec->setSize(size);
}
diff --git a/deps/icu-small/source/i18n/fphdlimp.h b/deps/icu-small/source/i18n/fphdlimp.h
index f3ac12c2bacb9a..2e9d5622b1b5b0 100644
--- a/deps/icu-small/source/i18n/fphdlimp.h
+++ b/deps/icu-small/source/i18n/fphdlimp.h
@@ -22,11 +22,16 @@ U_NAMESPACE_BEGIN
// base class, null implementation
class U_I18N_API FieldPositionHandler: public UMemory {
+ protected:
+ int32_t fShift = 0;
+
public:
virtual ~FieldPositionHandler();
- virtual void addAttribute(int32_t id, int32_t start, int32_t limit);
- virtual void shiftLast(int32_t delta);
- virtual UBool isRecording(void) const;
+ virtual void addAttribute(int32_t id, int32_t start, int32_t limit) = 0;
+ virtual void shiftLast(int32_t delta) = 0;
+ virtual UBool isRecording(void) const = 0;
+
+ void setShift(int32_t delta);
};
@@ -39,9 +44,9 @@ class FieldPositionOnlyHandler : public FieldPositionHandler {
FieldPositionOnlyHandler(FieldPosition& pos);
virtual ~FieldPositionOnlyHandler();
- virtual void addAttribute(int32_t id, int32_t start, int32_t limit);
- virtual void shiftLast(int32_t delta);
- virtual UBool isRecording(void) const;
+ void addAttribute(int32_t id, int32_t start, int32_t limit) U_OVERRIDE;
+ void shiftLast(int32_t delta) U_OVERRIDE;
+ UBool isRecording(void) const U_OVERRIDE;
};
@@ -63,9 +68,9 @@ class FieldPositionIteratorHandler : public FieldPositionHandler {
FieldPositionIteratorHandler(FieldPositionIterator* posIter, UErrorCode& status);
~FieldPositionIteratorHandler();
- virtual void addAttribute(int32_t id, int32_t start, int32_t limit);
- virtual void shiftLast(int32_t delta);
- virtual UBool isRecording(void) const;
+ void addAttribute(int32_t id, int32_t start, int32_t limit) U_OVERRIDE;
+ void shiftLast(int32_t delta) U_OVERRIDE;
+ UBool isRecording(void) const U_OVERRIDE;
};
U_NAMESPACE_END
diff --git a/deps/icu-small/source/i18n/measunit.cpp b/deps/icu-small/source/i18n/measunit.cpp
index e21afcba029e04..dc156aa720aae0 100644
--- a/deps/icu-small/source/i18n/measunit.cpp
+++ b/deps/icu-small/source/i18n/measunit.cpp
@@ -41,21 +41,21 @@ static const int32_t gOffsets[] = {
16,
20,
24,
- 285,
- 295,
- 306,
- 310,
- 316,
- 320,
- 340,
- 341,
+ 321,
+ 331,
+ 342,
+ 346,
352,
- 355,
- 361,
- 366,
- 370,
- 374,
- 399
+ 356,
+ 376,
+ 377,
+ 388,
+ 391,
+ 397,
+ 402,
+ 406,
+ 410,
+ 435
};
static const int32_t gIndexes[] = {
@@ -136,15 +136,18 @@ static const char * const gSubTypes[] = {
"AED",
"AFA",
"AFN",
+ "ALK",
"ALL",
"AMD",
"ANG",
"AOA",
+ "AOK",
"AON",
"AOR",
"ARA",
"ARP",
"ARS",
+ "ARY",
"ATS",
"AUD",
"AWG",
@@ -158,6 +161,8 @@ static const char * const gSubTypes[] = {
"BEC",
"BEF",
"BEL",
+ "BGJ",
+ "BGK",
"BGL",
"BGN",
"BHD",
@@ -165,7 +170,9 @@ static const char * const gSubTypes[] = {
"BMD",
"BND",
"BOB",
+ "BOP",
"BOV",
+ "BRB",
"BRC",
"BRE",
"BRL",
@@ -173,6 +180,7 @@ static const char * const gSubTypes[] = {
"BRR",
"BSD",
"BTN",
+ "BUK",
"BWP",
"BYB",
"BYN",
@@ -191,6 +199,7 @@ static const char * const gSubTypes[] = {
"COU",
"CRC",
"CSD",
+ "CSJ",
"CSK",
"CUC",
"CUP",
@@ -225,10 +234,13 @@ static const char * const gSubTypes[] = {
"GHS",
"GIP",
"GMD",
+ "GNE",
"GNF",
+ "GNS",
"GQE",
"GRD",
"GTQ",
+ "GWE",
"GWP",
"GYD",
"HKD",
@@ -239,10 +251,13 @@ static const char * const gSubTypes[] = {
"HUF",
"IDR",
"IEP",
+ "ILP",
+ "ILR",
"ILS",
"INR",
"IQD",
"IRR",
+ "ISJ",
"ISK",
"ITL",
"JMD",
@@ -257,11 +272,13 @@ static const char * const gSubTypes[] = {
"KWD",
"KYD",
"KZT",
+ "LAJ",
"LAK",
"LBP",
"LKR",
"LRD",
"LSL",
+ "LSM",
"LTL",
"LTT",
"LUC",
@@ -280,17 +297,23 @@ static const char * const gSubTypes[] = {
"MNT",
"MOP",
"MRO",
+ "MRU",
"MTL",
+ "MTP",
"MUR",
+ "MVQ",
"MVR",
"MWK",
"MXN",
+ "MXP",
"MXV",
"MYR",
+ "MZE",
"MZM",
"MZN",
"NAD",
"NGN",
+ "NIC",
"NIO",
"NLG",
"NOK",
@@ -298,6 +321,7 @@ static const char * const gSubTypes[] = {
"NZD",
"OMR",
"PAB",
+ "PEH",
"PEI",
"PEN",
"PES",
@@ -309,6 +333,8 @@ static const char * const gSubTypes[] = {
"PTE",
"PYG",
"QAR",
+ "RHD",
+ "ROK",
"ROL",
"RON",
"RSD",
@@ -320,6 +346,7 @@ static const char * const gSubTypes[] = {
"SCR",
"SDD",
"SDG",
+ "SDP",
"SEK",
"SGD",
"SHP",
@@ -331,6 +358,8 @@ static const char * const gSubTypes[] = {
"SRG",
"SSP",
"STD",
+ "STN",
+ "SUR",
"SVC",
"SYP",
"SZL",
@@ -349,15 +378,20 @@ static const char * const gSubTypes[] = {
"TZS",
"UAH",
"UAK",
+ "UGS",
+ "UGW",
"UGX",
"USD",
"USN",
"USS",
"UYI",
+ "UYN",
+ "UYP",
"UYU",
"UZS",
"VEB",
"VEF",
+ "VNC",
"VND",
"VUV",
"WST",
@@ -381,6 +415,7 @@ static const char * const gSubTypes[] = {
"XXX",
"YDD",
"YER",
+ "YUD",
"YUM",
"YUN",
"ZAL",
@@ -389,6 +424,7 @@ static const char * const gSubTypes[] = {
"ZMW",
"ZRN",
"ZRZ",
+ "ZWC",
"ZWD",
"ZWL",
"ZWN",
@@ -511,16 +547,20 @@ static const char * const gSubTypes[] = {
// Must be sorted by first value and then second value.
static int32_t unitPerUnitToSingleUnit[][4] = {
- {327, 297, 17, 0},
- {329, 303, 17, 2},
- {331, 297, 17, 3},
- {331, 388, 4, 2},
- {331, 389, 4, 3},
- {346, 386, 3, 1},
- {349, 11, 16, 4},
- {391, 327, 4, 1}
+ {363, 333, 17, 0},
+ {365, 339, 17, 2},
+ {367, 333, 17, 3},
+ {367, 424, 4, 2},
+ {367, 425, 4, 3},
+ {382, 422, 3, 1},
+ {385, 11, 16, 4},
+ {427, 363, 4, 1}
};
+// Shortcuts to the base unit in order to make the default constructor fast
+static const int32_t kBaseTypeIdx = 14;
+static const int32_t kBaseSubTypeIdx = 0;
+
MeasureUnit *MeasureUnit::createGForce(UErrorCode &status) {
return MeasureUnit::create(0, 0, status);
}
@@ -1082,7 +1122,8 @@ static int32_t binarySearch(
MeasureUnit::MeasureUnit() {
fCurrency[0] = 0;
- initNoUnit("base");
+ fTypeId = kBaseTypeIdx;
+ fSubTypeId = kBaseSubTypeIdx;
}
MeasureUnit::MeasureUnit(const MeasureUnit &other)
diff --git a/deps/icu-small/source/i18n/msgfmt.cpp b/deps/icu-small/source/i18n/msgfmt.cpp
index 064585665ae5e6..8b3807e67148a4 100644
--- a/deps/icu-small/source/i18n/msgfmt.cpp
+++ b/deps/icu-small/source/i18n/msgfmt.cpp
@@ -31,6 +31,7 @@
#include "unicode/decimfmt.h"
#include "unicode/localpointer.h"
#include "unicode/msgfmt.h"
+#include "unicode/numberformatter.h"
#include "unicode/plurfmt.h"
#include "unicode/rbnf.h"
#include "unicode/selfmt.h"
@@ -48,7 +49,7 @@
#include "ustrfmt.h"
#include "util.h"
#include "uvector.h"
-#include "visibledigits.h"
+#include "number_decimalquantity.h"
// *****************************************************************************
// class MessageFormat
@@ -1700,12 +1701,21 @@ Format* MessageFormat::createAppropriateFormat(UnicodeString& type, UnicodeStrin
formattableType = Formattable::kLong;
fmt = createIntegerFormat(fLocale, ec);
break;
- default: // pattern
- fmt = NumberFormat::createInstance(fLocale, ec);
- if (fmt) {
- DecimalFormat* decfmt = dynamic_cast(fmt);
- if (decfmt != NULL) {
- decfmt->applyPattern(style,parseError,ec);
+ default: // pattern or skeleton
+ int32_t i = 0;
+ for (; PatternProps::isWhiteSpace(style.charAt(i)); i++);
+ if (style.compare(i, 2, u"::", 0, 2) == 0) {
+ // Skeleton
+ UnicodeString skeleton = style.tempSubString(i + 2);
+ fmt = number::NumberFormatter::forSkeleton(skeleton, ec).locale(fLocale).toFormat(ec);
+ } else {
+ // Pattern
+ fmt = NumberFormat::createInstance(fLocale, ec);
+ if (fmt) {
+ auto* decfmt = dynamic_cast(fmt);
+ if (decfmt != nullptr) {
+ decfmt->applyPattern(style, parseError, ec);
+ }
}
}
break;
@@ -1959,14 +1969,14 @@ UnicodeString MessageFormat::PluralSelectorProvider::select(void *ctx, double nu
return UnicodeString(FALSE, OTHER_STRING, 5);
}
context.formatter->format(context.number, context.numberString, ec);
- const DecimalFormat *decFmt = dynamic_cast(context.formatter);
+ auto* decFmt = dynamic_cast(context.formatter);
if(decFmt != NULL) {
- VisibleDigitsWithExponent digits;
- decFmt->initVisibleDigitsWithExponent(context.number, digits, ec);
+ number::impl::DecimalQuantity dq;
+ decFmt->formatToDecimalQuantity(context.number, dq, ec);
if (U_FAILURE(ec)) {
return UnicodeString(FALSE, OTHER_STRING, 5);
}
- return rules->select(digits);
+ return rules->select(dq);
} else {
return rules->select(number);
}
diff --git a/deps/icu-small/source/i18n/nfsubs.cpp b/deps/icu-small/source/i18n/nfsubs.cpp
index ea817453d87c18..3733f0ca74d3e3 100644
--- a/deps/icu-small/source/i18n/nfsubs.cpp
+++ b/deps/icu-small/source/i18n/nfsubs.cpp
@@ -19,8 +19,9 @@
#include "utypeinfo.h" // for 'typeid' to work
#include "nfsubs.h"
-#include "digitlst.h"
#include "fmtableimp.h"
+#include "putilimp.h"
+#include "number_decimalquantity.h"
#if U_HAVE_RBNF
@@ -47,6 +48,8 @@ static const UChar gGreaterGreaterThan[] =
U_NAMESPACE_BEGIN
+using number::impl::DecimalQuantity;
+
class SameValueSubstitution : public NFSubstitution {
public:
SameValueSubstitution(int32_t pos,
@@ -1069,13 +1072,12 @@ FractionalPartSubstitution::doSubstitution(double number, UnicodeString& toInser
// numberToFormat /= 10;
// }
- DigitList dl;
- dl.set(number);
- dl.roundFixedPoint(20); // round to 20 fraction digits.
- dl.reduce(); // Removes any trailing zeros.
+ DecimalQuantity dl;
+ dl.setToDouble(number);
+ dl.roundToMagnitude(-20, UNUM_ROUND_HALFEVEN, status); // round to 20 fraction digits.
UBool pad = FALSE;
- for (int32_t didx = dl.getCount()-1; didx>=dl.getDecimalAt(); didx--) {
+ for (int32_t didx = dl.getLowerDisplayMagnitude(); didx<0; didx++) {
// Loop iterates over fraction digits, starting with the LSD.
// include both real digits from the number, and zeros
// to the left of the MSD but to the right of the decimal point.
@@ -1084,7 +1086,7 @@ FractionalPartSubstitution::doSubstitution(double number, UnicodeString& toInser
} else {
pad = TRUE;
}
- int64_t digit = didx>=0 ? dl.getDigit(didx) - '0' : 0;
+ int64_t digit = dl.getDigit(didx);
getRuleSet()->format(digit, toInsertInto, _pos + getPos(), recursionCount, status);
}
@@ -1142,7 +1144,8 @@ FractionalPartSubstitution::doParse(const UnicodeString& text,
int32_t digit;
// double p10 = 0.1;
- DigitList dl;
+ DecimalQuantity dl;
+ int32_t totalDigits = 0;
NumberFormat* fmt = NULL;
while (workText.length() > 0 && workPos.getIndex() != 0) {
workPos.setIndex(0);
@@ -1170,7 +1173,8 @@ FractionalPartSubstitution::doParse(const UnicodeString& text,
}
if (workPos.getIndex() != 0) {
- dl.append((char)('0' + digit));
+ dl.appendDigit(static_cast(digit), 0, true);
+ totalDigits++;
// result += digit * p10;
// p10 /= 10;
parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex());
@@ -1183,7 +1187,8 @@ FractionalPartSubstitution::doParse(const UnicodeString& text,
}
delete fmt;
- result = dl.getCount() == 0 ? 0 : dl.getDouble();
+ dl.adjustMagnitude(-totalDigits);
+ result = dl.toDouble();
result = composeRuleValue(result, baseValue);
resVal.setDouble(result);
return TRUE;
diff --git a/deps/icu-small/source/i18n/number_affixutils.cpp b/deps/icu-small/source/i18n/number_affixutils.cpp
index df4b267af5a004..8da29a03d52d56 100644
--- a/deps/icu-small/source/i18n/number_affixutils.cpp
+++ b/deps/icu-small/source/i18n/number_affixutils.cpp
@@ -3,21 +3,25 @@
#include "unicode/utypes.h"
-#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT
+#if !UCONFIG_NO_FORMATTING
#include "number_affixutils.h"
#include "unicode/utf16.h"
+#include "unicode/uniset.h"
using namespace icu;
using namespace icu::number;
using namespace icu::number::impl;
-int32_t AffixUtils::estimateLength(const CharSequence &patternString, UErrorCode &status) {
+TokenConsumer::~TokenConsumer() = default;
+SymbolProvider::~SymbolProvider() = default;
+
+int32_t AffixUtils::estimateLength(const UnicodeString &patternString, UErrorCode &status) {
AffixPatternState state = STATE_BASE;
int32_t offset = 0;
int32_t length = 0;
for (; offset < patternString.length();) {
- UChar32 cp = patternString.codePointAt(offset);
+ UChar32 cp = patternString.char32At(offset);
switch (state) {
case STATE_BASE:
@@ -78,12 +82,12 @@ int32_t AffixUtils::estimateLength(const CharSequence &patternString, UErrorCode
return length;
}
-UnicodeString AffixUtils::escape(const CharSequence &input) {
+UnicodeString AffixUtils::escape(const UnicodeString &input) {
AffixPatternState state = STATE_BASE;
int32_t offset = 0;
UnicodeString output;
for (; offset < input.length();) {
- UChar32 cp = input.codePointAt(offset);
+ UChar32 cp = input.char32At(offset);
switch (cp) {
case u'\'':
@@ -153,7 +157,7 @@ Field AffixUtils::getFieldForType(AffixPatternType type) {
}
int32_t
-AffixUtils::unescape(const CharSequence &affixPattern, NumberStringBuilder &output, int32_t position,
+AffixUtils::unescape(const UnicodeString &affixPattern, NumberStringBuilder &output, int32_t position,
const SymbolProvider &provider, UErrorCode &status) {
int32_t length = 0;
AffixTag tag;
@@ -173,7 +177,7 @@ AffixUtils::unescape(const CharSequence &affixPattern, NumberStringBuilder &outp
return length;
}
-int32_t AffixUtils::unescapedCodePointCount(const CharSequence &affixPattern,
+int32_t AffixUtils::unescapedCodePointCount(const UnicodeString &affixPattern,
const SymbolProvider &provider, UErrorCode &status) {
int32_t length = 0;
AffixTag tag;
@@ -192,7 +196,7 @@ int32_t AffixUtils::unescapedCodePointCount(const CharSequence &affixPattern,
}
bool
-AffixUtils::containsType(const CharSequence &affixPattern, AffixPatternType type, UErrorCode &status) {
+AffixUtils::containsType(const UnicodeString &affixPattern, AffixPatternType type, UErrorCode &status) {
if (affixPattern.length() == 0) {
return false;
}
@@ -207,7 +211,7 @@ AffixUtils::containsType(const CharSequence &affixPattern, AffixPatternType type
return false;
}
-bool AffixUtils::hasCurrencySymbols(const CharSequence &affixPattern, UErrorCode &status) {
+bool AffixUtils::hasCurrencySymbols(const UnicodeString &affixPattern, UErrorCode &status) {
if (affixPattern.length() == 0) {
return false;
}
@@ -222,9 +226,9 @@ bool AffixUtils::hasCurrencySymbols(const CharSequence &affixPattern, UErrorCode
return false;
}
-UnicodeString AffixUtils::replaceType(const CharSequence &affixPattern, AffixPatternType type,
+UnicodeString AffixUtils::replaceType(const UnicodeString &affixPattern, AffixPatternType type,
char16_t replacementChar, UErrorCode &status) {
- UnicodeString output = affixPattern.toUnicodeString();
+ UnicodeString output(affixPattern); // copy
if (affixPattern.length() == 0) {
return output;
};
@@ -239,11 +243,41 @@ UnicodeString AffixUtils::replaceType(const CharSequence &affixPattern, AffixPat
return output;
}
-AffixTag AffixUtils::nextToken(AffixTag tag, const CharSequence &patternString, UErrorCode &status) {
+bool AffixUtils::containsOnlySymbolsAndIgnorables(const UnicodeString& affixPattern,
+ const UnicodeSet& ignorables, UErrorCode& status) {
+ if (affixPattern.length() == 0) {
+ return true;
+ };
+ AffixTag tag;
+ while (hasNext(tag, affixPattern)) {
+ tag = nextToken(tag, affixPattern, status);
+ if (U_FAILURE(status)) { return false; }
+ if (tag.type == TYPE_CODEPOINT && !ignorables.contains(tag.codePoint)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void AffixUtils::iterateWithConsumer(const UnicodeString& affixPattern, TokenConsumer& consumer,
+ UErrorCode& status) {
+ if (affixPattern.length() == 0) {
+ return;
+ };
+ AffixTag tag;
+ while (hasNext(tag, affixPattern)) {
+ tag = nextToken(tag, affixPattern, status);
+ if (U_FAILURE(status)) { return; }
+ consumer.consumeToken(tag.type, tag.codePoint, status);
+ if (U_FAILURE(status)) { return; }
+ }
+}
+
+AffixTag AffixUtils::nextToken(AffixTag tag, const UnicodeString &patternString, UErrorCode &status) {
int32_t offset = tag.offset;
int32_t state = tag.state;
for (; offset < patternString.length();) {
- UChar32 cp = patternString.codePointAt(offset);
+ UChar32 cp = patternString.char32At(offset);
int32_t count = U16_LENGTH(cp);
switch (state) {
@@ -382,7 +416,7 @@ AffixTag AffixUtils::nextToken(AffixTag tag, const CharSequence &patternString,
}
}
-bool AffixUtils::hasNext(const AffixTag &tag, const CharSequence &string) {
+bool AffixUtils::hasNext(const AffixTag &tag, const UnicodeString &string) {
// First check for the {-1} and default initializer syntax.
if (tag.offset < 0) {
return false;
diff --git a/deps/icu-small/source/i18n/number_affixutils.h b/deps/icu-small/source/i18n/number_affixutils.h
index fd76c99b975566..1d7e1a115e046a 100644
--- a/deps/icu-small/source/i18n/number_affixutils.h
+++ b/deps/icu-small/source/i18n/number_affixutils.h
@@ -3,7 +3,7 @@
#include "unicode/utypes.h"
-#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT
+#if !UCONFIG_NO_FORMATTING
#ifndef __NUMBER_AFFIXUTILS_H__
#define __NUMBER_AFFIXUTILS_H__
@@ -12,6 +12,7 @@
#include "unicode/stringpiece.h"
#include "unicode/unistr.h"
#include "number_stringbuilder.h"
+#include "unicode/uniset.h"
U_NAMESPACE_BEGIN namespace number {
namespace impl {
@@ -37,19 +38,27 @@ struct AffixTag {
AffixPatternState state;
AffixPatternType type;
- AffixTag() : offset(0), state(STATE_BASE) {}
+ AffixTag()
+ : offset(0), state(STATE_BASE) {}
- AffixTag(int32_t offset) : offset(offset) {}
+ AffixTag(int32_t offset)
+ : offset(offset) {}
AffixTag(int32_t offset, UChar32 codePoint, AffixPatternState state, AffixPatternType type)
- : offset(offset), codePoint(codePoint), state(state), type(type)
- {}
+ : offset(offset), codePoint(codePoint), state(state), type(type) {}
+};
+
+class TokenConsumer {
+ public:
+ virtual ~TokenConsumer();
+
+ virtual void consumeToken(AffixPatternType type, UChar32 cp, UErrorCode& status) = 0;
};
// Exported as U_I18N_API because it is a base class for other exported types
class U_I18N_API SymbolProvider {
public:
- virtual ~SymbolProvider() = default;
+ virtual ~SymbolProvider();
// TODO: Could this be more efficient if it returned by reference?
virtual UnicodeString getSymbol(AffixPatternType type) const = 0;
@@ -107,7 +116,7 @@ class U_I18N_API AffixUtils {
* @param patternString The original string whose width will be estimated.
* @return The length of the unescaped string.
*/
- static int32_t estimateLength(const CharSequence &patternString, UErrorCode &status);
+ static int32_t estimateLength(const UnicodeString& patternString, UErrorCode& status);
/**
* Takes a string and escapes (quotes) characters that have special meaning in the affix pattern
@@ -118,7 +127,7 @@ class U_I18N_API AffixUtils {
* @param input The string to be escaped.
* @return The resulting UnicodeString.
*/
- static UnicodeString escape(const CharSequence &input);
+ static UnicodeString escape(const UnicodeString& input);
static Field getFieldForType(AffixPatternType type);
@@ -134,9 +143,8 @@ class U_I18N_API AffixUtils {
* @param position The index into the NumberStringBuilder to insert the string.
* @param provider An object to generate locale symbols.
*/
- static int32_t
- unescape(const CharSequence &affixPattern, NumberStringBuilder &output, int32_t position,
- const SymbolProvider &provider, UErrorCode &status);
+ static int32_t unescape(const UnicodeString& affixPattern, NumberStringBuilder& output,
+ int32_t position, const SymbolProvider& provider, UErrorCode& status);
/**
* Sames as {@link #unescape}, but only calculates the code point count. More efficient than {@link #unescape}
@@ -146,8 +154,8 @@ class U_I18N_API AffixUtils {
* @param provider An object to generate locale symbols.
* @return The same return value as if you called {@link #unescape}.
*/
- static int32_t unescapedCodePointCount(const CharSequence &affixPattern,
- const SymbolProvider &provider, UErrorCode &status);
+ static int32_t unescapedCodePointCount(const UnicodeString& affixPattern,
+ const SymbolProvider& provider, UErrorCode& status);
/**
* Checks whether the given affix pattern contains at least one token of the given type, which is
@@ -157,8 +165,7 @@ class U_I18N_API AffixUtils {
* @param type The token type.
* @return true if the affix pattern contains the given token type; false otherwise.
*/
- static bool
- containsType(const CharSequence &affixPattern, AffixPatternType type, UErrorCode &status);
+ static bool containsType(const UnicodeString& affixPattern, AffixPatternType type, UErrorCode& status);
/**
* Checks whether the specified affix pattern has any unquoted currency symbols ("¤").
@@ -166,7 +173,7 @@ class U_I18N_API AffixUtils {
* @param affixPattern The string to check for currency symbols.
* @return true if the literal has at least one unquoted currency symbol; false otherwise.
*/
- static bool hasCurrencySymbols(const CharSequence &affixPattern, UErrorCode &status);
+ static bool hasCurrencySymbols(const UnicodeString& affixPattern, UErrorCode& status);
/**
* Replaces all occurrences of tokens with the given type with the given replacement char.
@@ -176,9 +183,21 @@ class U_I18N_API AffixUtils {
* @param replacementChar The char to substitute in place of chars of the given token type.
* @return A string containing the new affix pattern.
*/
- static UnicodeString
- replaceType(const CharSequence &affixPattern, AffixPatternType type, char16_t replacementChar,
- UErrorCode &status);
+ static UnicodeString replaceType(const UnicodeString& affixPattern, AffixPatternType type,
+ char16_t replacementChar, UErrorCode& status);
+
+ /**
+ * Returns whether the given affix pattern contains only symbols and ignorables as defined by the
+ * given ignorables set.
+ */
+ static bool containsOnlySymbolsAndIgnorables(const UnicodeString& affixPattern,
+ const UnicodeSet& ignorables, UErrorCode& status);
+
+ /**
+ * Iterates over the affix pattern, calling the TokenConsumer for each token.
+ */
+ static void iterateWithConsumer(const UnicodeString& affixPattern, TokenConsumer& consumer,
+ UErrorCode& status);
/**
* Returns the next token from the affix pattern.
@@ -190,7 +209,7 @@ class U_I18N_API AffixUtils {
* (never negative), or -1 if there were no more tokens in the affix pattern.
* @see #hasNext
*/
- static AffixTag nextToken(AffixTag tag, const CharSequence &patternString, UErrorCode &status);
+ static AffixTag nextToken(AffixTag tag, const UnicodeString& patternString, UErrorCode& status);
/**
* Returns whether the affix pattern string has any more tokens to be retrieved from a call to
@@ -200,7 +219,7 @@ class U_I18N_API AffixUtils {
* @param string The affix pattern.
* @return true if there are more tokens to consume; false otherwise.
*/
- static bool hasNext(const AffixTag &tag, const CharSequence &string);
+ static bool hasNext(const AffixTag& tag, const UnicodeString& string);
private:
/**
@@ -208,8 +227,8 @@ class U_I18N_API AffixUtils {
* The order of the arguments is consistent with Java, but the order of the stored
* fields is not necessarily the same.
*/
- static inline AffixTag
- makeTag(int32_t offset, AffixPatternType type, AffixPatternState state, UChar32 cp) {
+ static inline AffixTag makeTag(int32_t offset, AffixPatternType type, AffixPatternState state,
+ UChar32 cp) {
return {offset, cp, state, type};
}
};
diff --git a/deps/icu-small/source/i18n/number_asformat.cpp b/deps/icu-small/source/i18n/number_asformat.cpp
new file mode 100644
index 00000000000000..c6bb538932cec8
--- /dev/null
+++ b/deps/icu-small/source/i18n/number_asformat.cpp
@@ -0,0 +1,105 @@
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+// Allow implicit conversion from char16_t* to UnicodeString for this file:
+// Helpful in toString methods and elsewhere.
+#define UNISTR_FROM_STRING_EXPLICIT
+
+#include
+#include
+#include "number_asformat.h"
+#include "number_types.h"
+#include "number_utils.h"
+#include "fphdlimp.h"
+#include "number_utypes.h"
+
+using namespace icu;
+using namespace icu::number;
+using namespace icu::number::impl;
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LocalizedNumberFormatterAsFormat)
+
+LocalizedNumberFormatterAsFormat::LocalizedNumberFormatterAsFormat(
+ const LocalizedNumberFormatter& formatter, const Locale& locale)
+ : fFormatter(formatter), fLocale(locale) {
+ const char* localeName = locale.getName();
+ setLocaleIDs(localeName, localeName);
+}
+
+LocalizedNumberFormatterAsFormat::~LocalizedNumberFormatterAsFormat() = default;
+
+UBool LocalizedNumberFormatterAsFormat::operator==(const Format& other) const {
+ auto* _other = dynamic_cast(&other);
+ if (_other == nullptr) {
+ return false;
+ }
+ // TODO: Change this to use LocalizedNumberFormatter::operator== if it is ever proposed.
+ // This implementation is fine, but not particularly efficient.
+ UErrorCode localStatus = U_ZERO_ERROR;
+ return fFormatter.toSkeleton(localStatus) == _other->fFormatter.toSkeleton(localStatus);
+}
+
+Format* LocalizedNumberFormatterAsFormat::clone() const {
+ return new LocalizedNumberFormatterAsFormat(*this);
+}
+
+UnicodeString& LocalizedNumberFormatterAsFormat::format(const Formattable& obj, UnicodeString& appendTo,
+ FieldPosition& pos, UErrorCode& status) const {
+ if (U_FAILURE(status)) { return appendTo; }
+ UFormattedNumberData data;
+ obj.populateDecimalQuantity(data.quantity, status);
+ if (U_FAILURE(status)) {
+ return appendTo;
+ }
+ fFormatter.formatImpl(&data, status);
+ if (U_FAILURE(status)) {
+ return appendTo;
+ }
+ // always return first occurrence:
+ pos.setBeginIndex(0);
+ pos.setEndIndex(0);
+ bool found = data.string.nextFieldPosition(pos, status);
+ if (found && appendTo.length() != 0) {
+ pos.setBeginIndex(pos.getBeginIndex() + appendTo.length());
+ pos.setEndIndex(pos.getEndIndex() + appendTo.length());
+ }
+ appendTo.append(data.string.toTempUnicodeString());
+ return appendTo;
+}
+
+UnicodeString& LocalizedNumberFormatterAsFormat::format(const Formattable& obj, UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) { return appendTo; }
+ UFormattedNumberData data;
+ obj.populateDecimalQuantity(data.quantity, status);
+ if (U_FAILURE(status)) {
+ return appendTo;
+ }
+ fFormatter.formatImpl(&data, status);
+ if (U_FAILURE(status)) {
+ return appendTo;
+ }
+ appendTo.append(data.string.toTempUnicodeString());
+ if (posIter != nullptr) {
+ FieldPositionIteratorHandler fpih(posIter, status);
+ data.string.getAllFieldPositions(fpih, status);
+ }
+ return appendTo;
+}
+
+void LocalizedNumberFormatterAsFormat::parseObject(const UnicodeString&, Formattable&,
+ ParsePosition& parse_pos) const {
+ // Not supported.
+ parse_pos.setErrorIndex(0);
+}
+
+const LocalizedNumberFormatter& LocalizedNumberFormatterAsFormat::getNumberFormatter() const {
+ return fFormatter;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/deps/icu-small/source/i18n/number_asformat.h b/deps/icu-small/source/i18n/number_asformat.h
new file mode 100644
index 00000000000000..bf82d72ae302a4
--- /dev/null
+++ b/deps/icu-small/source/i18n/number_asformat.h
@@ -0,0 +1,107 @@
+// © 2017 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+#ifndef __NUMBER_ASFORMAT_H__
+#define __NUMBER_ASFORMAT_H__
+
+#include "unicode/numberformatter.h"
+#include "number_types.h"
+#include "number_decimalquantity.h"
+#include "number_scientific.h"
+#include "number_patternstring.h"
+#include "number_modifiers.h"
+#include "number_multiplier.h"
+#include "number_roundingutils.h"
+#include "decNumber.h"
+#include "charstr.h"
+
+U_NAMESPACE_BEGIN namespace number {
+namespace impl {
+
+/**
+ * A wrapper around LocalizedNumberFormatter implementing the Format interface, enabling improved
+ * compatibility with other APIs.
+ *
+ * @draft ICU 62
+ * @see NumberFormatter
+ */
+class U_I18N_API LocalizedNumberFormatterAsFormat : public Format {
+ public:
+ LocalizedNumberFormatterAsFormat(const LocalizedNumberFormatter& formatter, const Locale& locale);
+
+ /**
+ * Destructor.
+ */
+ ~LocalizedNumberFormatterAsFormat() U_OVERRIDE;
+
+ /**
+ * Equals operator.
+ */
+ UBool operator==(const Format& other) const U_OVERRIDE;
+
+ /**
+ * Creates a copy of this object.
+ */
+ Format* clone() const U_OVERRIDE;
+
+ /**
+ * Formats a Number using the wrapped LocalizedNumberFormatter. The provided formattable must be a
+ * number type.
+ */
+ UnicodeString& format(const Formattable& obj, UnicodeString& appendTo, FieldPosition& pos,
+ UErrorCode& status) const U_OVERRIDE;
+
+ /**
+ * Formats a Number using the wrapped LocalizedNumberFormatter. The provided formattable must be a
+ * number type.
+ */
+ UnicodeString& format(const Formattable& obj, UnicodeString& appendTo, FieldPositionIterator* posIter,
+ UErrorCode& status) const U_OVERRIDE;
+
+ /**
+ * Not supported: sets an error index and returns.
+ */
+ void parseObject(const UnicodeString& source, Formattable& result,
+ ParsePosition& parse_pos) const U_OVERRIDE;
+
+ /**
+ * Gets the LocalizedNumberFormatter that this wrapper class uses to format numbers.
+ *
+ * For maximum efficiency, this function returns by const reference. You must copy the return value
+ * into a local variable if you want to use it beyond the lifetime of the current object:
+ *
+ *
+ * LocalizedNumberFormatter localFormatter = fmt->getNumberFormatter();
+ *
+ *
+ * You can however use the return value directly when chaining:
+ *
+ *
+ * FormattedNumber result = fmt->getNumberFormatter().formatDouble(514.23, status);
+ *
+ *
+ * @return The unwrapped LocalizedNumberFormatter.
+ */
+ const LocalizedNumberFormatter& getNumberFormatter() const;
+
+ UClassID getDynamicClassID() const U_OVERRIDE;
+ static UClassID U_EXPORT2 getStaticClassID();
+
+ private:
+ LocalizedNumberFormatter fFormatter;
+
+ // Even though the locale is inside the LocalizedNumberFormatter, we have to keep it here, too, because
+ // LocalizedNumberFormatter doesn't have a getLocale() method, and ICU-TC didn't want to add one.
+ Locale fLocale;
+};
+
+} // namespace impl
+} // namespace number
+U_NAMESPACE_END
+
+#endif // __NUMBER_ASFORMAT_H__
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/deps/icu-small/source/i18n/number_capi.cpp b/deps/icu-small/source/i18n/number_capi.cpp
new file mode 100644
index 00000000000000..37ad8bd76fcd72
--- /dev/null
+++ b/deps/icu-small/source/i18n/number_capi.cpp
@@ -0,0 +1,213 @@
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+// Allow implicit conversion from char16_t* to UnicodeString for this file:
+// Helpful in toString methods and elsewhere.
+#define UNISTR_FROM_STRING_EXPLICIT
+
+#include "fphdlimp.h"
+#include "number_utypes.h"
+#include "numparse_types.h"
+#include "unicode/numberformatter.h"
+#include "unicode/unumberformatter.h"
+
+using namespace icu;
+using namespace icu::number;
+using namespace icu::number::impl;
+
+
+//////////////////////////////////
+/// C API CONVERSION FUNCTIONS ///
+//////////////////////////////////
+
+UNumberFormatterData* UNumberFormatterData::validate(UNumberFormatter* input, UErrorCode& status) {
+ auto* constInput = static_cast(input);
+ auto* validated = validate(constInput, status);
+ return const_cast(validated);
+}
+
+const UNumberFormatterData*
+UNumberFormatterData::validate(const UNumberFormatter* input, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ if (input == nullptr) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return nullptr;
+ }
+ auto* impl = reinterpret_cast(input);
+ if (impl->fMagic != UNumberFormatterData::kMagic) {
+ status = U_INVALID_FORMAT_ERROR;
+ return nullptr;
+ }
+ return impl;
+}
+
+UNumberFormatter* UNumberFormatterData::exportForC() {
+ return reinterpret_cast(this);
+}
+
+UFormattedNumberData* UFormattedNumberData::validate(UFormattedNumber* input, UErrorCode& status) {
+ auto* constInput = static_cast(input);
+ auto* validated = validate(constInput, status);
+ return const_cast(validated);
+}
+
+const UFormattedNumberData*
+UFormattedNumberData::validate(const UFormattedNumber* input, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return nullptr;
+ }
+ if (input == nullptr) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return nullptr;
+ }
+ auto* impl = reinterpret_cast(input);
+ if (impl->fMagic != UFormattedNumberData::kMagic) {
+ status = U_INVALID_FORMAT_ERROR;
+ return nullptr;
+ }
+ return impl;
+}
+
+UFormattedNumber* UFormattedNumberData::exportForC() {
+ return reinterpret_cast(this);
+}
+
+/////////////////////////////////////
+/// END CAPI CONVERSION FUNCTIONS ///
+/////////////////////////////////////
+
+
+U_CAPI UNumberFormatter* U_EXPORT2
+unumf_openForSkeletonAndLocale(const UChar* skeleton, int32_t skeletonLen, const char* locale,
+ UErrorCode* ec) {
+ auto* impl = new UNumberFormatterData();
+ if (impl == nullptr) {
+ *ec = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+ // Readonly-alias constructor (first argument is whether we are NUL-terminated)
+ UnicodeString skeletonString(skeletonLen == -1, skeleton, skeletonLen);
+ impl->fFormatter = NumberFormatter::forSkeleton(skeletonString, *ec).locale(locale);
+ return impl->exportForC();
+}
+
+U_CAPI UFormattedNumber* U_EXPORT2
+unumf_openResult(UErrorCode* ec) {
+ auto* impl = new UFormattedNumberData();
+ if (impl == nullptr) {
+ *ec = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+ return impl->exportForC();
+}
+
+U_CAPI void U_EXPORT2
+unumf_formatInt(const UNumberFormatter* uformatter, int64_t value, UFormattedNumber* uresult,
+ UErrorCode* ec) {
+ const UNumberFormatterData* formatter = UNumberFormatterData::validate(uformatter, *ec);
+ UFormattedNumberData* result = UFormattedNumberData::validate(uresult, *ec);
+ if (U_FAILURE(*ec)) { return; }
+
+ result->string.clear();
+ result->quantity.setToLong(value);
+ formatter->fFormatter.formatImpl(result, *ec);
+}
+
+U_CAPI void U_EXPORT2
+unumf_formatDouble(const UNumberFormatter* uformatter, double value, UFormattedNumber* uresult,
+ UErrorCode* ec) {
+ const UNumberFormatterData* formatter = UNumberFormatterData::validate(uformatter, *ec);
+ UFormattedNumberData* result = UFormattedNumberData::validate(uresult, *ec);
+ if (U_FAILURE(*ec)) { return; }
+
+ result->string.clear();
+ result->quantity.setToDouble(value);
+ formatter->fFormatter.formatImpl(result, *ec);
+}
+
+U_CAPI void U_EXPORT2
+unumf_formatDecimal(const UNumberFormatter* uformatter, const char* value, int32_t valueLen,
+ UFormattedNumber* uresult, UErrorCode* ec) {
+ const UNumberFormatterData* formatter = UNumberFormatterData::validate(uformatter, *ec);
+ UFormattedNumberData* result = UFormattedNumberData::validate(uresult, *ec);
+ if (U_FAILURE(*ec)) { return; }
+
+ result->string.clear();
+ result->quantity.setToDecNumber({value, valueLen}, *ec);
+ if (U_FAILURE(*ec)) { return; }
+ formatter->fFormatter.formatImpl(result, *ec);
+}
+
+U_CAPI int32_t U_EXPORT2
+unumf_resultToString(const UFormattedNumber* uresult, UChar* buffer, int32_t bufferCapacity,
+ UErrorCode* ec) {
+ const UFormattedNumberData* result = UFormattedNumberData::validate(uresult, *ec);
+ if (U_FAILURE(*ec)) { return 0; }
+
+ if (buffer == nullptr ? bufferCapacity != 0 : bufferCapacity < 0) {
+ *ec = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ return result->string.toTempUnicodeString().extract(buffer, bufferCapacity, *ec);
+}
+
+U_CAPI UBool U_EXPORT2
+unumf_resultNextFieldPosition(const UFormattedNumber* uresult, UFieldPosition* ufpos, UErrorCode* ec) {
+ const UFormattedNumberData* result = UFormattedNumberData::validate(uresult, *ec);
+ if (U_FAILURE(*ec)) { return FALSE; }
+
+ if (ufpos == nullptr) {
+ *ec = U_ILLEGAL_ARGUMENT_ERROR;
+ return FALSE;
+ }
+
+ FieldPosition fp;
+ fp.setField(ufpos->field);
+ fp.setBeginIndex(ufpos->beginIndex);
+ fp.setEndIndex(ufpos->endIndex);
+ bool retval = result->string.nextFieldPosition(fp, *ec);
+ ufpos->beginIndex = fp.getBeginIndex();
+ ufpos->endIndex = fp.getEndIndex();
+ // NOTE: MSVC sometimes complains when implicitly converting between bool and UBool
+ return retval ? TRUE : FALSE;
+}
+
+U_CAPI void U_EXPORT2
+unumf_resultGetAllFieldPositions(const UFormattedNumber* uresult, UFieldPositionIterator* ufpositer,
+ UErrorCode* ec) {
+ const UFormattedNumberData* result = UFormattedNumberData::validate(uresult, *ec);
+ if (U_FAILURE(*ec)) { return; }
+
+ if (ufpositer == nullptr) {
+ *ec = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ auto* fpi = reinterpret_cast(ufpositer);
+ FieldPositionIteratorHandler fpih(fpi, *ec);
+ result->string.getAllFieldPositions(fpih, *ec);
+}
+
+U_CAPI void U_EXPORT2
+unumf_closeResult(UFormattedNumber* uresult) {
+ UErrorCode localStatus = U_ZERO_ERROR;
+ const UFormattedNumberData* impl = UFormattedNumberData::validate(uresult, localStatus);
+ delete impl;
+}
+
+U_CAPI void U_EXPORT2
+unumf_close(UNumberFormatter* f) {
+ UErrorCode localStatus = U_ZERO_ERROR;
+ const UNumberFormatterData* impl = UNumberFormatterData::validate(f, localStatus);
+ delete impl;
+}
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/deps/icu-small/source/i18n/number_compact.cpp b/deps/icu-small/source/i18n/number_compact.cpp
index cc0d8fd2a20cce..40278e1a012e54 100644
--- a/deps/icu-small/source/i18n/number_compact.cpp
+++ b/deps/icu-small/source/i18n/number_compact.cpp
@@ -3,14 +3,15 @@
#include "unicode/utypes.h"
-#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT
+#if !UCONFIG_NO_FORMATTING
-#include "resource.h"
-#include "number_compact.h"
#include "unicode/ustring.h"
#include "unicode/ures.h"
#include "cstring.h"
#include "charstr.h"
+#include "resource.h"
+#include "number_compact.h"
+#include "number_microprops.h"
#include "uresimp.h"
using namespace icu;
@@ -275,15 +276,15 @@ void CompactHandler::processQuantity(DecimalQuantity &quantity, MicroProps &micr
int magnitude;
if (quantity.isZero()) {
magnitude = 0;
- micros.rounding.apply(quantity, status);
+ micros.rounder.apply(quantity, status);
} else {
// TODO: Revisit chooseMultiplierAndApply
- int multiplier = micros.rounding.chooseMultiplierAndApply(quantity, data, status);
+ int multiplier = micros.rounder.chooseMultiplierAndApply(quantity, data, status);
magnitude = quantity.isZero() ? 0 : quantity.getMagnitude();
magnitude -= multiplier;
}
- StandardPlural::Form plural = quantity.getStandardPlural(rules);
+ StandardPlural::Form plural = utils::getStandardPlural(rules, quantity);
const UChar *patternString = data.getPattern(magnitude, plural);
if (patternString == nullptr) {
// Use the default (non-compact) modifier.
@@ -313,7 +314,7 @@ void CompactHandler::processQuantity(DecimalQuantity &quantity, MicroProps &micr
}
// We already performed rounding. Do not perform it again.
- micros.rounding = Rounder::constructPassThrough();
+ micros.rounder = RoundingImpl::passThrough();
}
#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/deps/icu-small/source/i18n/number_compact.h b/deps/icu-small/source/i18n/number_compact.h
index f7adf36416e92f..dda5f9f9b2dc91 100644
--- a/deps/icu-small/source/i18n/number_compact.h
+++ b/deps/icu-small/source/i18n/number_compact.h
@@ -3,7 +3,7 @@
#include "unicode/utypes.h"
-#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT
+#if !UCONFIG_NO_FORMATTING
#ifndef __NUMBER_COMPACT_H__
#define __NUMBER_COMPACT_H__
diff --git a/deps/icu-small/source/i18n/number_currencysymbols.cpp b/deps/icu-small/source/i18n/number_currencysymbols.cpp
new file mode 100644
index 00000000000000..0b79d6596f18c0
--- /dev/null
+++ b/deps/icu-small/source/i18n/number_currencysymbols.cpp
@@ -0,0 +1,123 @@
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+// Allow implicit conversion from char16_t* to UnicodeString for this file:
+// Helpful in toString methods and elsewhere.
+#define UNISTR_FROM_STRING_EXPLICIT
+
+#include "numparse_types.h"
+#include "number_currencysymbols.h"
+
+using namespace icu;
+using namespace icu::number;
+using namespace icu::number::impl;
+
+
+CurrencySymbols::CurrencySymbols(CurrencyUnit currency, const Locale& locale, UErrorCode& status)
+ : fCurrency(currency), fLocaleName(locale.getName(), status) {
+ fCurrencySymbol.setToBogus();
+ fIntlCurrencySymbol.setToBogus();
+}
+
+CurrencySymbols::CurrencySymbols(CurrencyUnit currency, const Locale& locale,
+ const DecimalFormatSymbols& symbols, UErrorCode& status)
+ : CurrencySymbols(currency, locale, status) {
+ // If either of the overrides is present, save it in the local UnicodeString.
+ if (symbols.isCustomCurrencySymbol()) {
+ fCurrencySymbol = symbols.getConstSymbol(DecimalFormatSymbols::kCurrencySymbol);
+ }
+ if (symbols.isCustomIntlCurrencySymbol()) {
+ fIntlCurrencySymbol = symbols.getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol);
+ }
+}
+
+const char16_t* CurrencySymbols::getIsoCode() const {
+ return fCurrency.getISOCurrency();
+}
+
+UnicodeString CurrencySymbols::getNarrowCurrencySymbol(UErrorCode& status) const {
+ // Note: currently no override is available for narrow currency symbol
+ return loadSymbol(UCURR_NARROW_SYMBOL_NAME, status);
+}
+
+UnicodeString CurrencySymbols::getCurrencySymbol(UErrorCode& status) const {
+ if (!fCurrencySymbol.isBogus()) {
+ return fCurrencySymbol;
+ }
+ return loadSymbol(UCURR_SYMBOL_NAME, status);
+}
+
+UnicodeString CurrencySymbols::loadSymbol(UCurrNameStyle selector, UErrorCode& status) const {
+ const char16_t* isoCode = fCurrency.getISOCurrency();
+ UBool ignoredIsChoiceFormatFillIn = FALSE;
+ int32_t symbolLen = 0;
+ const char16_t* symbol = ucurr_getName(
+ isoCode,
+ fLocaleName.data(),
+ selector,
+ &ignoredIsChoiceFormatFillIn,
+ &symbolLen,
+ &status);
+ // If given an unknown currency, ucurr_getName returns the input string, which we can't alias safely!
+ // Otherwise, symbol points to a resource bundle, and we can use readonly-aliasing constructor.
+ if (symbol == isoCode) {
+ return UnicodeString(isoCode, 3);
+ } else {
+ return UnicodeString(TRUE, symbol, symbolLen);
+ }
+}
+
+UnicodeString CurrencySymbols::getIntlCurrencySymbol(UErrorCode&) const {
+ if (!fIntlCurrencySymbol.isBogus()) {
+ return fIntlCurrencySymbol;
+ }
+ // Note: Not safe to use readonly-aliasing constructor here because the buffer belongs to this object,
+ // which could be destructed or moved during the lifetime of the return value.
+ return UnicodeString(fCurrency.getISOCurrency(), 3);
+}
+
+UnicodeString CurrencySymbols::getPluralName(StandardPlural::Form plural, UErrorCode& status) const {
+ const char16_t* isoCode = fCurrency.getISOCurrency();
+ UBool isChoiceFormat = FALSE;
+ int32_t symbolLen = 0;
+ const char16_t* symbol = ucurr_getPluralName(
+ isoCode,
+ fLocaleName.data(),
+ &isChoiceFormat,
+ StandardPlural::getKeyword(plural),
+ &symbolLen,
+ &status);
+ // If given an unknown currency, ucurr_getName returns the input string, which we can't alias safely!
+ // Otherwise, symbol points to a resource bundle, and we can use readonly-aliasing constructor.
+ if (symbol == isoCode) {
+ return UnicodeString(isoCode, 3);
+ } else {
+ return UnicodeString(TRUE, symbol, symbolLen);
+ }
+}
+
+
+CurrencyUnit
+icu::number::impl::resolveCurrency(const DecimalFormatProperties& properties, const Locale& locale,
+ UErrorCode& status) {
+ if (!properties.currency.isNull()) {
+ return properties.currency.getNoError();
+ } else {
+ UErrorCode localStatus = U_ZERO_ERROR;
+ char16_t buf[4] = {};
+ ucurr_forLocale(locale.getName(), buf, 4, &localStatus);
+ if (U_SUCCESS(localStatus)) {
+ return CurrencyUnit(buf, status);
+ } else {
+ // Default currency (XXX)
+ return CurrencyUnit();
+ }
+ }
+}
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/deps/icu-small/source/i18n/number_currencysymbols.h b/deps/icu-small/source/i18n/number_currencysymbols.h
new file mode 100644
index 00000000000000..9996bf96ae08a1
--- /dev/null
+++ b/deps/icu-small/source/i18n/number_currencysymbols.h
@@ -0,0 +1,65 @@
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+#ifndef __SOURCE_NUMBER_CURRENCYSYMBOLS_H__
+#define __SOURCE_NUMBER_CURRENCYSYMBOLS_H__
+
+#include "numparse_types.h"
+#include "charstr.h"
+#include "number_decimfmtprops.h"
+
+U_NAMESPACE_BEGIN namespace number {
+namespace impl {
+
+
+// Exported as U_I18N_API for tests
+class U_I18N_API CurrencySymbols : public UMemory {
+ public:
+ CurrencySymbols() = default; // default constructor: leaves class in valid but undefined state
+
+ /** Creates an instance in which all symbols are loaded from data. */
+ CurrencySymbols(CurrencyUnit currency, const Locale& locale, UErrorCode& status);
+
+ /** Creates an instance in which some symbols might be pre-populated. */
+ CurrencySymbols(CurrencyUnit currency, const Locale& locale, const DecimalFormatSymbols& symbols,
+ UErrorCode& status);
+
+ const char16_t* getIsoCode() const;
+
+ UnicodeString getNarrowCurrencySymbol(UErrorCode& status) const;
+
+ UnicodeString getCurrencySymbol(UErrorCode& status) const;
+
+ UnicodeString getIntlCurrencySymbol(UErrorCode& status) const;
+
+ UnicodeString getPluralName(StandardPlural::Form plural, UErrorCode& status) const;
+
+ protected:
+ // Required fields:
+ CurrencyUnit fCurrency;
+ CharString fLocaleName;
+
+ // Optional fields:
+ UnicodeString fCurrencySymbol;
+ UnicodeString fIntlCurrencySymbol;
+
+ UnicodeString loadSymbol(UCurrNameStyle selector, UErrorCode& status) const;
+};
+
+
+/**
+ * Resolves the effective currency from the property bag.
+ */
+CurrencyUnit
+resolveCurrency(const DecimalFormatProperties& properties, const Locale& locale, UErrorCode& status);
+
+
+} // namespace impl
+} // namespace numparse
+U_NAMESPACE_END
+
+#endif //__SOURCE_NUMBER_CURRENCYSYMBOLS_H__
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/deps/icu-small/source/i18n/number_decimalquantity.cpp b/deps/icu-small/source/i18n/number_decimalquantity.cpp
index b68df26ba26167..9d80e3349cb8aa 100644
--- a/deps/icu-small/source/i18n/number_decimalquantity.cpp
+++ b/deps/icu-small/source/i18n/number_decimalquantity.cpp
@@ -3,25 +3,30 @@
#include "unicode/utypes.h"
-#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT
+#if !UCONFIG_NO_FORMATTING
-#include "uassert.h"
+#include
#include
-#include "cmemory.h"
-#include "decNumber.h"
#include
+#include
+
+#include "unicode/plurrule.h"
+#include "cmemory.h"
+#include "number_decnum.h"
+#include "putilimp.h"
#include "number_decimalquantity.h"
-#include "decContext.h"
-#include "decNumber.h"
#include "number_roundingutils.h"
#include "double-conversion.h"
-#include "unicode/plurrule.h"
+#include "charstr.h"
+#include "number_utils.h"
+#include "uassert.h"
using namespace icu;
using namespace icu::number;
using namespace icu::number::impl;
using icu::double_conversion::DoubleToStringConverter;
+using icu::double_conversion::StringToDoubleConverter;
namespace {
@@ -29,25 +34,6 @@ int8_t NEGATIVE_FLAG = 1;
int8_t INFINITY_FLAG = 2;
int8_t NAN_FLAG = 4;
-static constexpr int32_t DEFAULT_DIGITS = 34;
-typedef MaybeStackHeaderAndArray DecNumberWithStorage;
-
-/** Helper function to convert a decNumber-compatible string into a decNumber. */
-void stringToDecNumber(StringPiece n, DecNumberWithStorage &dn) {
- decContext set;
- uprv_decContextDefault(&set, DEC_INIT_BASE);
- uprv_decContextSetRounding(&set, DEC_ROUND_HALF_EVEN);
- set.traps = 0; // no traps, thank you
- if (n.length() > DEFAULT_DIGITS) {
- dn.resize(n.length(), 0);
- set.digits = n.length();
- } else {
- set.digits = DEFAULT_DIGITS;
- }
- uprv_decNumberFromString(dn.getAlias(), n.data(), &set);
- U_ASSERT(DECDPUN == 1);
-}
-
/** Helper function for safe subtraction (no overflow). */
inline int32_t safeSubtract(int32_t a, int32_t b) {
// Note: In C++, signed integer subtraction is undefined behavior.
@@ -83,6 +69,7 @@ static double DOUBLE_MULTIPLIERS[] = {
} // namespace
+icu::IFixedDecimal::~IFixedDecimal() = default;
DecimalQuantity::DecimalQuantity() {
setBcdToZero();
@@ -101,11 +88,30 @@ DecimalQuantity::DecimalQuantity(const DecimalQuantity &other) {
*this = other;
}
+DecimalQuantity::DecimalQuantity(DecimalQuantity&& src) U_NOEXCEPT {
+ *this = std::move(src);
+}
+
DecimalQuantity &DecimalQuantity::operator=(const DecimalQuantity &other) {
if (this == &other) {
return *this;
}
copyBcdFrom(other);
+ copyFieldsFrom(other);
+ return *this;
+}
+
+DecimalQuantity& DecimalQuantity::operator=(DecimalQuantity&& src) U_NOEXCEPT {
+ if (this == &src) {
+ return *this;
+ }
+ moveBcdFrom(src);
+ copyFieldsFrom(src);
+ return *this;
+}
+
+void DecimalQuantity::copyFieldsFrom(const DecimalQuantity& other) {
+ bogus = other.bogus;
lOptPos = other.lOptPos;
lReqPos = other.lReqPos;
rReqPos = other.rReqPos;
@@ -116,7 +122,6 @@ DecimalQuantity &DecimalQuantity::operator=(const DecimalQuantity &other) {
origDouble = other.origDouble;
origDelta = other.origDelta;
isApproximate = other.isApproximate;
- return *this;
}
void DecimalQuantity::clear() {
@@ -129,10 +134,16 @@ void DecimalQuantity::clear() {
}
void DecimalQuantity::setIntegerLength(int32_t minInt, int32_t maxInt) {
- // Validation should happen outside of DecimalQuantity, e.g., in the Rounder class.
+ // Validation should happen outside of DecimalQuantity, e.g., in the Precision class.
U_ASSERT(minInt >= 0);
U_ASSERT(maxInt >= minInt);
+ // Special behavior: do not set minInt to be less than what is already set.
+ // This is so significant digits rounding can set the integer length.
+ if (minInt < lReqPos) {
+ minInt = lReqPos;
+ }
+
// Save values into internal state
// Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE
lOptPos = maxInt;
@@ -140,7 +151,7 @@ void DecimalQuantity::setIntegerLength(int32_t minInt, int32_t maxInt) {
}
void DecimalQuantity::setFractionLength(int32_t minFrac, int32_t maxFrac) {
- // Validation should happen outside of DecimalQuantity, e.g., in the Rounder class.
+ // Validation should happen outside of DecimalQuantity, e.g., in the Precision class.
U_ASSERT(minFrac >= 0);
U_ASSERT(maxFrac >= minFrac);
@@ -160,29 +171,53 @@ uint64_t DecimalQuantity::getPositionFingerprint() const {
}
void DecimalQuantity::roundToIncrement(double roundingIncrement, RoundingMode roundingMode,
- int32_t minMaxFrac, UErrorCode& status) {
- // TODO: This is innefficient. Improve?
- // TODO: Should we convert to decNumber instead?
+ int32_t maxFrac, UErrorCode& status) {
+ // TODO(13701): This is innefficient. Improve?
+ // TODO(13701): Should we convert to decNumber instead?
+ roundToInfinity();
double temp = toDouble();
temp /= roundingIncrement;
- setToDouble(temp);
- roundToMagnitude(0, roundingMode, status);
- temp = toDouble();
+ // Use another DecimalQuantity to perform the actual rounding...
+ DecimalQuantity dq;
+ dq.setToDouble(temp);
+ dq.roundToMagnitude(0, roundingMode, status);
+ temp = dq.toDouble();
temp *= roundingIncrement;
setToDouble(temp);
// Since we reset the value to a double, we need to specify the rounding boundary
// in order to get the DecimalQuantity out of approximation mode.
- roundToMagnitude(-minMaxFrac, roundingMode, status);
+ // NOTE: In Java, we have minMaxFrac, but in C++, the two are differentiated.
+ roundToMagnitude(-maxFrac, roundingMode, status);
}
-void DecimalQuantity::multiplyBy(int32_t multiplicand) {
+void DecimalQuantity::multiplyBy(const DecNum& multiplicand, UErrorCode& status) {
if (isInfinite() || isZero() || isNaN()) {
return;
}
- // TODO: Should we convert to decNumber instead?
- double temp = toDouble();
- temp *= multiplicand;
- setToDouble(temp);
+ // Convert to DecNum, multiply, and convert back.
+ DecNum decnum;
+ toDecNum(decnum, status);
+ if (U_FAILURE(status)) { return; }
+ decnum.multiplyBy(multiplicand, status);
+ if (U_FAILURE(status)) { return; }
+ setToDecNum(decnum, status);
+}
+
+void DecimalQuantity::divideBy(const DecNum& divisor, UErrorCode& status) {
+ if (isInfinite() || isZero() || isNaN()) {
+ return;
+ }
+ // Convert to DecNum, multiply, and convert back.
+ DecNum decnum;
+ toDecNum(decnum, status);
+ if (U_FAILURE(status)) { return; }
+ decnum.divideBy(divisor, status);
+ if (U_FAILURE(status)) { return; }
+ setToDecNum(decnum, status);
+}
+
+void DecimalQuantity::negate() {
+ flags ^= NEGATIVE_FLAG;
}
int32_t DecimalQuantity::getMagnitude() const {
@@ -190,21 +225,17 @@ int32_t DecimalQuantity::getMagnitude() const {
return scale + precision - 1;
}
-void DecimalQuantity::adjustMagnitude(int32_t delta) {
+bool DecimalQuantity::adjustMagnitude(int32_t delta) {
if (precision != 0) {
- scale += delta;
- origDelta += delta;
- }
-}
-
-StandardPlural::Form DecimalQuantity::getStandardPlural(const PluralRules *rules) const {
- if (rules == nullptr) {
- // Fail gracefully if the user didn't provide a PluralRules
- return StandardPlural::Form::OTHER;
- } else {
- UnicodeString ruleString = rules->select(*this);
- return StandardPlural::orOtherFromString(ruleString);
+ // i.e., scale += delta; origDelta += delta
+ bool overflow = uprv_add32_overflow(scale, delta, &scale);
+ overflow = uprv_add32_overflow(origDelta, delta, &origDelta) || overflow;
+ // Make sure that precision + scale won't overflow, either
+ int32_t dummy;
+ overflow = overflow || uprv_add32_overflow(scale, precision, &dummy);
+ return overflow;
}
+ return false;
}
double DecimalQuantity::getPluralOperand(PluralOperand operand) const {
@@ -214,7 +245,8 @@ double DecimalQuantity::getPluralOperand(PluralOperand operand) const {
switch (operand) {
case PLURAL_OPERAND_I:
- return static_cast(toLong());
+ // Invert the negative sign if necessary
+ return static_cast(isNegative() ? -toLong(true) : toLong(true));
case PLURAL_OPERAND_F:
return static_cast(toFractionLong(true));
case PLURAL_OPERAND_T:
@@ -228,6 +260,10 @@ double DecimalQuantity::getPluralOperand(PluralOperand operand) const {
}
}
+bool DecimalQuantity::hasIntegerValue() const {
+ return scale >= 0;
+}
+
int32_t DecimalQuantity::getUpperDisplayMagnitude() const {
// If this assertion fails, you need to call roundToInfinity() or some other rounding method.
// See the comment in the header file explaining the "isApproximate" field.
@@ -287,7 +323,10 @@ bool DecimalQuantity::isZero() const {
DecimalQuantity &DecimalQuantity::setToInt(int32_t n) {
setBcdToZero();
flags = 0;
- if (n < 0) {
+ if (n == INT32_MIN) {
+ flags |= NEGATIVE_FLAG;
+ // leave as INT32_MIN; handled below in _setToInt()
+ } else if (n < 0) {
flags |= NEGATIVE_FLAG;
n = -n;
}
@@ -309,7 +348,7 @@ void DecimalQuantity::_setToInt(int32_t n) {
DecimalQuantity &DecimalQuantity::setToLong(int64_t n) {
setBcdToZero();
flags = 0;
- if (n < 0) {
+ if (n < 0 && n > INT64_MIN) {
flags |= NEGATIVE_FLAG;
n = -n;
}
@@ -322,10 +361,12 @@ DecimalQuantity &DecimalQuantity::setToLong(int64_t n) {
void DecimalQuantity::_setToLong(int64_t n) {
if (n == INT64_MIN) {
- static const char *int64minStr = "9.223372036854775808E+18";
- DecNumberWithStorage dn;
- stringToDecNumber(int64minStr, dn);
- readDecNumberToBcd(dn.getAlias());
+ DecNum decnum;
+ UErrorCode localStatus = U_ZERO_ERROR;
+ decnum.setTo("9.223372036854775808E+18", localStatus);
+ if (U_FAILURE(localStatus)) { return; } // unexpected
+ flags |= NEGATIVE_FLAG;
+ readDecNumberToBcd(decnum);
} else if (n <= INT32_MAX) {
readIntToBcd(static_cast(n));
} else {
@@ -337,7 +378,7 @@ DecimalQuantity &DecimalQuantity::setToDouble(double n) {
setBcdToZero();
flags = 0;
// signbit() from handles +0.0 vs -0.0
- if (std::signbit(n) != 0) {
+ if (std::signbit(n)) {
flags |= NEGATIVE_FLAG;
n = -n;
}
@@ -424,51 +465,107 @@ void DecimalQuantity::convertToAccurateDouble() {
explicitExactDouble = true;
}
-DecimalQuantity &DecimalQuantity::setToDecNumber(StringPiece n) {
+DecimalQuantity &DecimalQuantity::setToDecNumber(StringPiece n, UErrorCode& status) {
setBcdToZero();
flags = 0;
- DecNumberWithStorage dn;
- stringToDecNumber(n, dn);
+ // Compute the decNumber representation
+ DecNum decnum;
+ decnum.setTo(n, status);
- // The code path for decNumber is modeled after BigDecimal in Java.
- if (decNumberIsNegative(dn.getAlias())) {
- flags |= NEGATIVE_FLAG;
- }
- if (!decNumberIsZero(dn.getAlias())) {
- _setToDecNumber(dn.getAlias());
- }
+ _setToDecNum(decnum, status);
return *this;
}
-void DecimalQuantity::_setToDecNumber(decNumber *n) {
- // Java fastpaths for ints here. In C++, just always read directly from the decNumber.
- readDecNumberToBcd(n);
- compact();
+DecimalQuantity& DecimalQuantity::setToDecNum(const DecNum& decnum, UErrorCode& status) {
+ setBcdToZero();
+ flags = 0;
+
+ _setToDecNum(decnum, status);
+ return *this;
}
-int64_t DecimalQuantity::toLong() const {
- int64_t result = 0L;
- for (int32_t magnitude = scale + precision - 1; magnitude >= 0; magnitude--) {
+void DecimalQuantity::_setToDecNum(const DecNum& decnum, UErrorCode& status) {
+ if (U_FAILURE(status)) { return; }
+ if (decnum.isNegative()) {
+ flags |= NEGATIVE_FLAG;
+ }
+ if (!decnum.isZero()) {
+ readDecNumberToBcd(decnum);
+ compact();
+ }
+}
+
+int64_t DecimalQuantity::toLong(bool truncateIfOverflow) const {
+ // NOTE: Call sites should be guarded by fitsInLong(), like this:
+ // if (dq.fitsInLong()) { /* use dq.toLong() */ } else { /* use some fallback */ }
+ // Fallback behavior upon truncateIfOverflow is to truncate at 17 digits.
+ uint64_t result = 0L;
+ int32_t upperMagnitude = std::min(scale + precision, lOptPos) - 1;
+ if (truncateIfOverflow) {
+ upperMagnitude = std::min(upperMagnitude, 17);
+ }
+ for (int32_t magnitude = upperMagnitude; magnitude >= 0; magnitude--) {
result = result * 10 + getDigitPos(magnitude - scale);
}
- return result;
+ if (isNegative()) {
+ return static_cast(0LL - result); // i.e., -result
+ }
+ return static_cast(result);
}
-int64_t DecimalQuantity::toFractionLong(bool includeTrailingZeros) const {
- int64_t result = 0L;
+uint64_t DecimalQuantity::toFractionLong(bool includeTrailingZeros) const {
+ uint64_t result = 0L;
int32_t magnitude = -1;
- for (; (magnitude >= scale || (includeTrailingZeros && magnitude >= rReqPos)) &&
- magnitude >= rOptPos; magnitude--) {
+ int32_t lowerMagnitude = std::max(scale, rOptPos);
+ if (includeTrailingZeros) {
+ lowerMagnitude = std::min(lowerMagnitude, rReqPos);
+ }
+ for (; magnitude >= lowerMagnitude && result <= 1e18L; magnitude--) {
result = result * 10 + getDigitPos(magnitude - scale);
}
+ // Remove trailing zeros; this can happen during integer overflow cases.
+ if (!includeTrailingZeros) {
+ while (result > 0 && (result % 10) == 0) {
+ result /= 10;
+ }
+ }
return result;
}
-double DecimalQuantity::toDouble() const {
- if (isApproximate) {
- return toDoubleFromOriginal();
+bool DecimalQuantity::fitsInLong(bool ignoreFraction) const {
+ if (isZero()) {
+ return true;
+ }
+ if (scale < 0 && !ignoreFraction) {
+ return false;
}
+ int magnitude = getMagnitude();
+ if (magnitude < 18) {
+ return true;
+ }
+ if (magnitude > 18) {
+ return false;
+ }
+ // Hard case: the magnitude is 10^18.
+ // The largest int64 is: 9,223,372,036,854,775,807
+ for (int p = 0; p < precision; p++) {
+ int8_t digit = getDigit(18 - p);
+ static int8_t INT64_BCD[] = { 9, 2, 2, 3, 3, 7, 2, 0, 3, 6, 8, 5, 4, 7, 7, 5, 8, 0, 8 };
+ if (digit < INT64_BCD[p]) {
+ return true;
+ } else if (digit > INT64_BCD[p]) {
+ return false;
+ }
+ }
+ // Exactly equal to max long plus one.
+ return isNegative();
+}
+
+double DecimalQuantity::toDouble() const {
+ // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
+ // See the comment in the header file explaining the "isApproximate" field.
+ U_ASSERT(!isApproximate);
if (isNaN()) {
return NAN;
@@ -476,42 +573,37 @@ double DecimalQuantity::toDouble() const {
return isNegative() ? -INFINITY : INFINITY;
}
- int64_t tempLong = 0L;
- int32_t lostDigits = precision - (precision < 17 ? precision : 17);
- for (int shift = precision - 1; shift >= lostDigits; shift--) {
- tempLong = tempLong * 10 + getDigitPos(shift);
+ // We are processing well-formed input, so we don't need any special options to StringToDoubleConverter.
+ StringToDoubleConverter converter(0, 0, 0, "", "");
+ UnicodeString numberString = this->toScientificString();
+ int32_t count;
+ return converter.StringToDouble(
+ reinterpret_cast(numberString.getBuffer()),
+ numberString.length(),
+ &count);
+}
+
+void DecimalQuantity::toDecNum(DecNum& output, UErrorCode& status) const {
+ // Special handling for zero
+ if (precision == 0) {
+ output.setTo("0", status);
}
- double result = static_cast(tempLong);
- int32_t _scale = scale + lostDigits;
- if (_scale >= 0) {
- // 1e22 is the largest exact double.
- int32_t i = _scale;
- for (; i >= 22; i -= 22) result *= 1e22;
- result *= DOUBLE_MULTIPLIERS[i];
- } else {
- // 1e22 is the largest exact double.
- int32_t i = _scale;
- for (; i <= -22; i += 22) result /= 1e22;
- result /= DOUBLE_MULTIPLIERS[-i];
+
+ // Use the BCD constructor. We need to do a little bit of work to convert, though.
+ // The decNumber constructor expects most-significant first, but we store least-significant first.
+ MaybeStackArray ubcd(precision);
+ for (int32_t m = 0; m < precision; m++) {
+ ubcd[precision - m - 1] = static_cast(getDigitPos(m));
}
- if (isNegative()) { result = -result; }
- return result;
+ output.setTo(ubcd.getAlias(), precision, scale, isNegative(), status);
}
-double DecimalQuantity::toDoubleFromOriginal() const {
- double result = origDouble;
- int32_t delta = origDelta;
- if (delta >= 0) {
- // 1e22 is the largest exact double.
- for (; delta >= 22; delta -= 22) result *= 1e22;
- result *= DOUBLE_MULTIPLIERS[delta];
- } else {
- // 1e22 is the largest exact double.
- for (; delta <= -22; delta += 22) result /= 1e22;
- result /= DOUBLE_MULTIPLIERS[-delta];
+void DecimalQuantity::truncate() {
+ if (scale < 0) {
+ shiftRight(-scale);
+ scale = 0;
+ compact();
}
- if (isNegative()) { result *= -1; }
- return result;
}
void DecimalQuantity::roundToMagnitude(int32_t magnitude, RoundingMode roundingMode, UErrorCode& status) {
@@ -689,17 +781,63 @@ void DecimalQuantity::appendDigit(int8_t value, int32_t leadingZeros, bool appen
}
UnicodeString DecimalQuantity::toPlainString() const {
+ U_ASSERT(!isApproximate);
UnicodeString sb;
if (isNegative()) {
sb.append(u'-');
}
+ if (precision == 0 || getMagnitude() < 0) {
+ sb.append(u'0');
+ }
for (int m = getUpperDisplayMagnitude(); m >= getLowerDisplayMagnitude(); m--) {
+ if (m == -1) { sb.append(u'.'); }
sb.append(getDigit(m) + u'0');
- if (m == 0) { sb.append(u'.'); }
}
return sb;
}
+UnicodeString DecimalQuantity::toScientificString() const {
+ U_ASSERT(!isApproximate);
+ UnicodeString result;
+ if (isNegative()) {
+ result.append(u'-');
+ }
+ if (precision == 0) {
+ result.append(u"0E+0", -1);
+ return result;
+ }
+ // NOTE: It is not safe to add to lOptPos (aka maxInt) or subtract from
+ // rOptPos (aka -maxFrac) due to overflow.
+ int32_t upperPos = std::min(precision + scale, lOptPos) - scale - 1;
+ int32_t lowerPos = std::max(scale, rOptPos) - scale;
+ int32_t p = upperPos;
+ result.append(u'0' + getDigitPos(p));
+ if ((--p) >= lowerPos) {
+ result.append(u'.');
+ for (; p >= lowerPos; p--) {
+ result.append(u'0' + getDigitPos(p));
+ }
+ }
+ result.append(u'E');
+ int32_t _scale = upperPos + scale;
+ if (_scale < 0) {
+ _scale *= -1;
+ result.append(u'-');
+ } else {
+ result.append(u'+');
+ }
+ if (_scale == 0) {
+ result.append(u'0');
+ }
+ int32_t insertIndex = result.length();
+ while (_scale > 0) {
+ std::div_t res = std::div(_scale, 10);
+ result.insert(insertIndex, u'0' + res.rem);
+ _scale = res.quot;
+ }
+ return result;
+}
+
////////////////////////////////////////////////////
/// End of DecimalQuantity_AbstractBCD.java ///
/// Start of DecimalQuantity_DualStorageBCD.java ///
@@ -707,7 +845,7 @@ UnicodeString DecimalQuantity::toPlainString() const {
int8_t DecimalQuantity::getDigitPos(int32_t position) const {
if (usingBytes) {
- if (position < 0 || position > precision) { return 0; }
+ if (position < 0 || position >= precision) { return 0; }
return fBCD.bcdBytes.ptr[position];
} else {
if (position < 0 || position >= 16) { return 0; }
@@ -819,7 +957,8 @@ void DecimalQuantity::readLongToBcd(int64_t n) {
}
}
-void DecimalQuantity::readDecNumberToBcd(decNumber *dn) {
+void DecimalQuantity::readDecNumberToBcd(const DecNum& decnum) {
+ const decNumber* dn = decnum.getRawDecNumber();
if (dn->digits > 16) {
ensureCapacity(dn->digits);
for (int32_t i = 0; i < dn->digits; i++) {
@@ -919,7 +1058,7 @@ void DecimalQuantity::ensureCapacity(int32_t capacity) {
auto bcd1 = static_cast