// Helpful in toString methods and elsewhere.
#define UNISTR_FROM_STRING_EXPLICIT
+#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"
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;
-DecimalFormat::DecimalFormat(UErrorCode& status) {}
+DecimalFormat::DecimalFormat(UErrorCode& status)
+ : DecimalFormat(nullptr, status) {
+}
-DecimalFormat::DecimalFormat(const UnicodeString& pattern, UErrorCode& status) {}
+DecimalFormat::DecimalFormat(const UnicodeString& pattern, UErrorCode& status)
+ : DecimalFormat(nullptr, status) {
+ setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
+ refreshFormatter(status);
+}
DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt,
- UErrorCode& status) {}
+ UErrorCode& status)
+ : DecimalFormat(symbolsToAdopt, status) {
+ setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
+}
DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt,
- UNumberFormatStyle style, UErrorCode& status) {}
+ 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 {
+ setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
+ }
+ refreshFormatter(status);
+}
+
+DecimalFormat::DecimalFormat(const DecimalFormatSymbols* symbolsToAdopt, UErrorCode& status) {
+ properties = new DecimalFormatProperties();
+ exportedProperties = new DecimalFormatProperties();
+ if (symbolsToAdopt == nullptr) {
+ symbols = new DecimalFormatSymbols(status);
+ } else {
+ symbols = symbolsToAdopt;
+ }
+ if (properties == nullptr || exportedProperties == nullptr || symbols == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+}
void DecimalFormat::setParseAllInput(UNumberFormatAttributeValue value) {}
void DecimalFormat::setContext(UDisplayContext value, UErrorCode& status) {}
DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt,
- UParseError& parseError, UErrorCode& status) {}
+ UParseError& parseError, UErrorCode& status)
+ : DecimalFormat(symbolsToAdopt, status) {
+ // TODO: What is parseError for?
+ setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
+ refreshFormatter(status);
+}
DecimalFormat::DecimalFormat(const UnicodeString& pattern, const DecimalFormatSymbols& symbols,
- UErrorCode& status) {}
-
-DecimalFormat::DecimalFormat(const DecimalFormat& source) {}
+ UErrorCode& status)
+ : DecimalFormat(new DecimalFormatSymbols(symbols), status) {
+ setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status);
+ refreshFormatter(status);
+}
+
+DecimalFormat::DecimalFormat(const DecimalFormat& source) {
+ properties = new DecimalFormatProperties();
+ exportedProperties = new DecimalFormatProperties();
+ symbols = new DecimalFormatSymbols(*source.symbols);
+ if (properties == nullptr || exportedProperties == nullptr || symbols == nullptr) {
+ return;
+ }
+ ErrorCode localStatus;
+ refreshFormatter(localStatus);
+}
DecimalFormat& DecimalFormat::operator=(const DecimalFormat& rhs) {}
UClassID DecimalFormat::getDynamicClassID() const {}
+/** Rebuilds the formatter object from the property bag. */
+void DecimalFormat::refreshFormatter(UErrorCode& status) {
+ if (exportedProperties == nullptr) {
+ // exportedProperties is null only when the formatter is not ready yet.
+ // The only time when this happens is during legacy deserialization.
+ return;
+ }
+ Locale locale = getLocale(ULOC_ACTUAL_LOCALE, status);
+ if (U_FAILURE(status)) {
+ // Constructor
+ locale = symbols->getLocale(ULOC_ACTUAL_LOCALE, status);
+ }
+ if (U_FAILURE(status)) {
+ // Deserialization
+ locale = symbols->getLocale();
+ }
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ *formatter = NumberPropertyMapper::create(*properties, *symbols, *exportedProperties, status).locale(
+ locale);
+ parser = NumberParserImpl::createParserFromProperties(*properties, *symbols, false, false, status);
+ parserWithCurrency = NumberParserImpl::createParserFromProperties(
+ *properties, *symbols, true, false, status);
+}
+
+void DecimalFormat::setPropertiesFromPattern(const UnicodeString& pattern, int32_t ignoreRounding,
+ UErrorCode& status) {
+ // Cast workaround to get around putting the enum in the public header file
+ auto actualIgnoreRounding = static_cast<IgnoreRounding>(ignoreRounding);
+ PatternParser::parseToExistingProperties(pattern, *properties, actualIgnoreRounding, status);
+}
+
#endif /* #if !UCONFIG_NO_FORMATTING */
namespace number {
namespace impl {
class DecimalQuantity;
+struct DecimalFormatProperties;
+}
+}
+
+namespace numparse {
+namespace impl {
+class NumberParserImpl;
}
}
* subclasses, such code will not necessarily work and will not be
* guaranteed to work stably from release to release.
*/
-class U_I18N_API DecimalFormat: public NumberFormat {
-public:
+class U_I18N_API DecimalFormat : public NumberFormat {
+ public:
/**
* Pad position.
* @stable ICU 2.4
*/
enum EPadPosition {
- kPadBeforePrefix,
- kPadAfterPrefix,
- kPadBeforeSuffix,
- kPadAfterSuffix
+ kPadBeforePrefix, kPadAfterPrefix, kPadBeforeSuffix, kPadAfterSuffix
};
/**
* pattern is invalid this will be set to a failure code.
* @stable ICU 2.0
*/
- DecimalFormat(const UnicodeString& pattern,
- UErrorCode& status);
+ DecimalFormat(const UnicodeString& pattern, UErrorCode& status);
/**
* Create a DecimalFormat from the given pattern and symbols.
* pattern is invalid this will be set to a failure code.
* @stable ICU 2.0
*/
- DecimalFormat( const UnicodeString& pattern,
- DecimalFormatSymbols* symbolsToAdopt,
- UErrorCode& status);
+ DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt, UErrorCode& status);
#ifndef U_HIDE_INTERNAL_API
+
/**
* This API is for ICU use only.
* Create a DecimalFormat from the given pattern, symbols, and style.
* pattern is invalid this will be set to a failure code.
* @internal
*/
- DecimalFormat( const UnicodeString& pattern,
- DecimalFormatSymbols* symbolsToAdopt,
- UNumberFormatStyle style,
- UErrorCode& status);
+ DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt,
+ UNumberFormatStyle style, UErrorCode& status);
+
+ /**
+ * This API is for ICU use only.
+ * Default internal constructor for DecimalFormat.
+ */
+ DecimalFormat(const DecimalFormatSymbols* symbolsToAdopt, UErrorCode& status);
#if UCONFIG_HAVE_PARSEALLINPUT
+
/**
* @internal
*/
void setParseAllInput(UNumberFormatAttributeValue value);
+
#endif
#endif /* U_HIDE_INTERNAL_API */
* @return *this - for chaining (example: format.setAttribute(...).setAttribute(...) )
* @stable ICU 51
*/
- virtual DecimalFormat& setAttribute( UNumberFormatAttribute attr,
- int32_t newvalue,
- UErrorCode &status);
+ virtual DecimalFormat& setAttribute(UNumberFormatAttribute attr, int32_t newvalue, UErrorCode& status);
/**
* Get an integer
* @return the attribute value. Undefined if there is an error.
* @stable ICU 51
*/
- virtual int32_t getAttribute( UNumberFormatAttribute attr,
- UErrorCode &status) const;
+ virtual int32_t getAttribute(UNumberFormatAttribute attr, UErrorCode& status) const;
/**
* pattern is invalid this will be set to a failure code.
* @stable ICU 2.0
*/
- DecimalFormat( const UnicodeString& pattern,
- DecimalFormatSymbols* symbolsToAdopt,
- UParseError& parseError,
- UErrorCode& status);
+ DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt,
+ UParseError& parseError, UErrorCode& status);
+
/**
* Create a DecimalFormat from the given pattern and symbols.
* Use this constructor when you need to completely customize the
* pattern is invalid this will be set to a failure code.
* @stable ICU 2.0
*/
- DecimalFormat( const UnicodeString& pattern,
- const DecimalFormatSymbols& symbols,
- UErrorCode& status);
+ DecimalFormat(const UnicodeString& pattern, const DecimalFormatSymbols& symbols, UErrorCode& status);
/**
* Copy constructor.
* @return Reference to 'appendTo' parameter.
* @stable ICU 2.0
*/
- UnicodeString& format(double number,
- UnicodeString& appendTo,
- FieldPosition& pos) const U_OVERRIDE;
+ UnicodeString& format(double number, UnicodeString& appendTo, FieldPosition& pos) const U_OVERRIDE;
/**
* @return Reference to 'appendTo' parameter.
* @internal
*/
- UnicodeString& format(double number,
- UnicodeString& appendTo,
- FieldPosition& pos,
- UErrorCode &status) const U_OVERRIDE;
+ UnicodeString& format(double number, UnicodeString& appendTo, FieldPosition& pos,
+ UErrorCode& status) const U_OVERRIDE;
/**
* Format a double or long number using base-10 representation.
* @return Reference to 'appendTo' parameter.
* @stable ICU 4.4
*/
- UnicodeString& format(double number,
- UnicodeString& appendTo,
- FieldPositionIterator* posIter,
+ UnicodeString& format(double number, UnicodeString& appendTo, FieldPositionIterator* posIter,
UErrorCode& status) const U_OVERRIDE;
/**
* @return Reference to 'appendTo' parameter.
* @stable ICU 2.0
*/
- UnicodeString& format(int32_t number,
- UnicodeString& appendTo,
- FieldPosition& pos) const U_OVERRIDE;
+ UnicodeString& format(int32_t number, UnicodeString& appendTo, FieldPosition& pos) const U_OVERRIDE;
/**
* Format a long number using base-10 representation.
* @return Reference to 'appendTo' parameter.
* @internal
*/
- UnicodeString& format(int32_t number,
- UnicodeString& appendTo,
- FieldPosition& pos,
- UErrorCode &status) const U_OVERRIDE;
+ UnicodeString& format(int32_t number, UnicodeString& appendTo, FieldPosition& pos,
+ UErrorCode& status) const U_OVERRIDE;
/**
* Format a long number using base-10 representation.
* @return Reference to 'appendTo' parameter.
* @stable ICU 4.4
*/
- UnicodeString& format(int32_t number,
- UnicodeString& appendTo,
- FieldPositionIterator* posIter,
+ UnicodeString& format(int32_t number, UnicodeString& appendTo, FieldPositionIterator* posIter,
UErrorCode& status) const U_OVERRIDE;
/**
* @return Reference to 'appendTo' parameter.
* @stable ICU 2.8
*/
- UnicodeString& format(int64_t number,
- UnicodeString& appendTo,
- FieldPosition& pos) const U_OVERRIDE;
+ UnicodeString& format(int64_t number, UnicodeString& appendTo, FieldPosition& pos) const U_OVERRIDE;
/**
* Format an int64 number using base-10 representation.
* @return Reference to 'appendTo' parameter.
* @internal
*/
- UnicodeString& format(int64_t number,
- UnicodeString& appendTo,
- FieldPosition& pos,
- UErrorCode &status) const U_OVERRIDE;
+ UnicodeString& format(int64_t number, UnicodeString& appendTo, FieldPosition& pos,
+ UErrorCode& status) const U_OVERRIDE;
/**
* Format an int64 number using base-10 representation.
* @return Reference to 'appendTo' parameter.
* @stable ICU 4.4
*/
- UnicodeString& format(int64_t number,
- UnicodeString& appendTo,
- FieldPositionIterator* posIter,
+ UnicodeString& format(int64_t number, UnicodeString& appendTo, FieldPositionIterator* posIter,
UErrorCode& status) const U_OVERRIDE;
/**
* @return Reference to 'appendTo' parameter.
* @stable ICU 4.4
*/
- UnicodeString& format(StringPiece number,
- UnicodeString& appendTo,
- FieldPositionIterator* posIter,
+ UnicodeString& format(StringPiece number, UnicodeString& appendTo, FieldPositionIterator* posIter,
UErrorCode& status) const U_OVERRIDE;
* @return Reference to 'appendTo' parameter.
* @internal
*/
- UnicodeString& format(const number::impl::DecimalQuantity &number,
- UnicodeString& appendTo,
- FieldPositionIterator* posIter,
- UErrorCode& status) const U_OVERRIDE;
+ UnicodeString& format(const number::impl::DecimalQuantity& number, UnicodeString& appendTo,
+ FieldPositionIterator* posIter, UErrorCode& status) const U_OVERRIDE;
/**
* Format a decimal number.
* @return Reference to 'appendTo' parameter.
* @internal
*/
- UnicodeString& format(const number::impl::DecimalQuantity &number,
- UnicodeString& appendTo,
- FieldPosition& pos,
- UErrorCode& status) const U_OVERRIDE;
+ UnicodeString& format(const number::impl::DecimalQuantity& number, UnicodeString& appendTo,
+ FieldPosition& pos, UErrorCode& status) const U_OVERRIDE;
+
+ using NumberFormat::parse;
- using NumberFormat::parse;
-
- /**
- * Parse the given string using this object's choices. The method
- * does string comparisons to try to find an optimal match.
- * If no object can be parsed, index is unchanged, and NULL is
- * returned. The result is returned as the most parsimonious
- * type of Formattable that will accomodate all of the
- * necessary precision. For example, if the result is exactly 12,
- * it will be returned as a long. However, if it is 1.5, it will
- * be returned as a double.
- *
- * @param text The text to be parsed.
- * @param result Formattable to be set to the parse result.
- * If parse fails, return contents are undefined.
- * @param parsePosition The position to start parsing at on input.
- * On output, moved to after the last successfully
- * parse character. On parse failure, does not change.
- * @see Formattable
- * @stable ICU 2.0
- */
- void parse(const UnicodeString& text,
- Formattable& result,
+ /**
+ * Parse the given string using this object's choices. The method
+ * does string comparisons to try to find an optimal match.
+ * If no object can be parsed, index is unchanged, and NULL is
+ * returned. The result is returned as the most parsimonious
+ * type of Formattable that will accomodate all of the
+ * necessary precision. For example, if the result is exactly 12,
+ * it will be returned as a long. However, if it is 1.5, it will
+ * be returned as a double.
+ *
+ * @param text The text to be parsed.
+ * @param result Formattable to be set to the parse result.
+ * If parse fails, return contents are undefined.
+ * @param parsePosition The position to start parsing at on input.
+ * On output, moved to after the last successfully
+ * parse character. On parse failure, does not change.
+ * @see Formattable
+ * @stable ICU 2.0
+ */
+ void parse(const UnicodeString& text, Formattable& result,
ParsePosition& parsePosition) const U_OVERRIDE;
/**
* the parsed currency; if parse fails, this is NULL.
* @stable ICU 49
*/
- CurrencyAmount* parseCurrency(const UnicodeString& text,
- ParsePosition& pos) const U_OVERRIDE;
+ CurrencyAmount* parseCurrency(const UnicodeString& text, ParsePosition& pos) const U_OVERRIDE;
/**
* Returns the decimal format symbols, which is generally not changed
* @see #setPadPosition
* @stable ICU 2.0
*/
- virtual void setPadCharacter(const UnicodeString &padChar);
+ virtual void setPadCharacter(const UnicodeString& padChar);
/**
* Get the position at which padding will take place. This is the location
#endif /* U_HIDE_INTERNAL_API */
- /* Cannot use #ifndef U_HIDE_INTERNAL_API for the following draft method since it is virtual. */
+ /* Cannot use #ifndef U_HIDE_INTERNAL_API for the following draft method since it is virtual. */
/**
* Sets the minimum grouping digits. Setting to a value less than or
* equal to 1 turns off minimum grouping digits.
* set to a failure result.
* @stable ICU 2.0
*/
- virtual void applyPattern(const UnicodeString& pattern,
- UParseError& parseError,
- UErrorCode& status);
+ virtual void applyPattern(const UnicodeString& pattern, UParseError& parseError, UErrorCode& status);
+
/**
* Sets the pattern.
* @param pattern The pattern to be applied.
* set to a failure result.
* @stable ICU 2.0
*/
- virtual void applyPattern(const UnicodeString& pattern,
- UErrorCode& status);
+ virtual void applyPattern(const UnicodeString& pattern, UErrorCode& status);
/**
* Apply the given pattern to this Format object. The pattern
* set to a failure result.
* @stable ICU 2.0
*/
- virtual void applyLocalizedPattern(const UnicodeString& pattern,
- UParseError& parseError,
+ virtual void applyLocalizedPattern(const UnicodeString& pattern, UParseError& parseError,
UErrorCode& status);
/**
* set to a failure result.
* @stable ICU 2.0
*/
- virtual void applyLocalizedPattern(const UnicodeString& pattern,
- UErrorCode& status);
+ virtual void applyLocalizedPattern(const UnicodeString& pattern, UErrorCode& status);
/**
UCurrencyUsage getCurrencyUsage() const;
#ifndef U_HIDE_INTERNAL_API
+
/**
* Format a number and save it into the given DecimalQuantity.
* Internal, not intended for public use.
*/
void formatToDecimalQuantity(const Formattable& number, number::impl::DecimalQuantity& output,
UErrorCode& status) const;
+
#endif
/**
*/
virtual UClassID getDynamicClassID(void) const U_OVERRIDE;
+ private:
+
+ /** Rebuilds the formatter object from the property bag. */
+ void refreshFormatter(UErrorCode& status);
+
+ /**
+ * Updates the property bag with settings from the given pattern.
+ *
+ * @param pattern The pattern string to parse.
+ * @param ignoreRounding Whether to leave out rounding information (minFrac, maxFrac, and rounding
+ * increment) when parsing the pattern. This may be desirable if a custom rounding mode, such
+ * as CurrencyUsage, is to be used instead. One of {@link
+ * PatternStringParser#IGNORE_ROUNDING_ALWAYS}, {@link PatternStringParser#IGNORE_ROUNDING_IF_CURRENCY},
+ * or {@link PatternStringParser#IGNORE_ROUNDING_NEVER}.
+ * @see PatternAndPropertyUtils#parseToExistingProperties
+ */
+ void setPropertiesFromPattern(const UnicodeString& pattern, int32_t ignoreRounding,
+ UErrorCode& status);
+
+ //=====================================================================================//
+ // INSTANCE FIELDS //
+ //=====================================================================================//
+
+ /**
+ * The property bag corresponding to user-specified settings and settings from the pattern string.
+ * In principle this should be final, but serialize and clone won't work if it is final. Does not
+ * need to be volatile because the reference never changes.
+ */
+ number::impl::DecimalFormatProperties* properties;
+
+ /**
+ * The symbols for the current locale. Volatile because threads may read and write at the same
+ * time.
+ */
+ const DecimalFormatSymbols* symbols;
+
+ /**
+ * The pre-computed formatter object. Setters cause this to be re-computed atomically. The {@link
+ * #format} method uses the formatter directly without needing to synchronize. Volatile because
+ * threads may read and write at the same time.
+ */
+ number::LocalizedNumberFormatter* formatter;
+
+ /**
+ * The effective properties as exported from the formatter object. Volatile because threads may
+ * read and write at the same time.
+ */
+ number::impl::DecimalFormatProperties* exportedProperties;
+
+ const numparse::impl::NumberParserImpl* parser;
+ const numparse::impl::NumberParserImpl* parserWithCurrency;
+
};
U_NAMESPACE_END