#include "unicode/ustring.h"
#include "unicode/basictz.h"
#include "unicode/simpleformatter.h"
+#include "unicode/simplenumberformatter.h"
#include "unicode/simpletz.h"
#include "unicode/rbtz.h"
#include "unicode/tzfmt.h"
if (fTimeZoneFormat) {
delete fTimeZoneFormat;
}
- freeFastNumberFormatters();
+ delete fSimpleNumberFormatter;
#if !UCONFIG_NO_BREAK_ITERATION
delete fCapitalizationBrkIter;
//----------------------------------------------------------------------
SimpleDateFormat::SimpleDateFormat(UErrorCode& status)
- : fLocale(Locale::getDefault()),
- fSymbols(NULL),
- fTimeZoneFormat(NULL),
- fSharedNumberFormatters(NULL),
- fCapitalizationBrkIter(NULL)
+ : fLocale(Locale::getDefault())
{
initializeBooleanAttributes();
construct(kShort, (EStyle) (kShort + kDateOffset), fLocale, status);
SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
UErrorCode &status)
: fPattern(pattern),
- fLocale(Locale::getDefault()),
- fSymbols(NULL),
- fTimeZoneFormat(NULL),
- fSharedNumberFormatters(NULL),
- fCapitalizationBrkIter(NULL)
+ fLocale(Locale::getDefault())
{
fDateOverride.setToBogus();
fTimeOverride.setToBogus();
const UnicodeString& override,
UErrorCode &status)
: fPattern(pattern),
- fLocale(Locale::getDefault()),
- fSymbols(NULL),
- fTimeZoneFormat(NULL),
- fSharedNumberFormatters(NULL),
- fCapitalizationBrkIter(NULL)
+ fLocale(Locale::getDefault())
{
fDateOverride.setTo(override);
fTimeOverride.setToBogus();
const Locale& locale,
UErrorCode& status)
: fPattern(pattern),
- fLocale(locale),
- fTimeZoneFormat(NULL),
- fSharedNumberFormatters(NULL),
- fCapitalizationBrkIter(NULL)
+ fLocale(locale)
{
fDateOverride.setToBogus();
const Locale& locale,
UErrorCode& status)
: fPattern(pattern),
- fLocale(locale),
- fTimeZoneFormat(NULL),
- fSharedNumberFormatters(NULL),
- fCapitalizationBrkIter(NULL)
+ fLocale(locale)
{
fDateOverride.setTo(override);
UErrorCode& status)
: fPattern(pattern),
fLocale(Locale::getDefault()),
- fSymbols(symbolsToAdopt),
- fTimeZoneFormat(NULL),
- fSharedNumberFormatters(NULL),
- fCapitalizationBrkIter(NULL)
+ fSymbols(symbolsToAdopt)
{
fDateOverride.setToBogus();
UErrorCode& status)
: fPattern(pattern),
fLocale(Locale::getDefault()),
- fSymbols(new DateFormatSymbols(symbols)),
- fTimeZoneFormat(NULL),
- fSharedNumberFormatters(NULL),
- fCapitalizationBrkIter(NULL)
+ fSymbols(new DateFormatSymbols(symbols))
{
fDateOverride.setToBogus();
EStyle dateStyle,
const Locale& locale,
UErrorCode& status)
-: fLocale(locale),
- fSymbols(NULL),
- fTimeZoneFormat(NULL),
- fSharedNumberFormatters(NULL),
- fCapitalizationBrkIter(NULL)
+: fLocale(locale)
{
initializeBooleanAttributes();
construct(timeStyle, dateStyle, fLocale, status);
SimpleDateFormat::SimpleDateFormat(const Locale& locale,
UErrorCode& status)
: fPattern(gDefaultPattern),
- fLocale(locale),
- fSymbols(NULL),
- fTimeZoneFormat(NULL),
- fSharedNumberFormatters(NULL),
- fCapitalizationBrkIter(NULL)
+ fLocale(locale)
{
if (U_FAILURE(status)) return;
initializeBooleanAttributes();
SimpleDateFormat::SimpleDateFormat(const SimpleDateFormat& other)
: DateFormat(other),
- fLocale(other.fLocale),
- fSymbols(NULL),
- fTimeZoneFormat(NULL),
- fSharedNumberFormatters(NULL),
- fCapitalizationBrkIter(NULL)
+ fLocale(other.fLocale)
{
initializeBooleanAttributes();
*this = other;
if (this == &other) {
return *this;
}
+
+ // fSimpleNumberFormatter references fNumberFormatter, delete it
+ // before we call the = operator which may invalidate fNumberFormatter
+ delete fSimpleNumberFormatter;
+ fSimpleNumberFormatter = nullptr;
+
DateFormat::operator=(other);
fDateOverride = other.fDateOverride;
fTimeOverride = other.fTimeOverride;
}
UErrorCode localStatus = U_ZERO_ERROR;
- freeFastNumberFormatters();
- initFastNumberFormatters(localStatus);
-
+ // SimpleNumberFormatter does not have a copy constructor. Furthermore,
+ // it references data from an internal field, fNumberFormatter,
+ // so we must rematerialize that reference after copying over the number formatter.
+ initSimpleNumberFormatter(localStatus);
return *this;
}
//fNumberFormat->setLenient(true); // Java uses a custom DateNumberFormat to format/parse
initNumberFormatters(locale, status);
- initFastNumberFormatters(status);
+ initSimpleNumberFormatter(status);
}
else if (U_SUCCESS(status))
//----------------------------------------------------------------------
-static number::LocalizedNumberFormatter*
-createFastFormatter(const DecimalFormat* df, int32_t minInt, int32_t maxInt, UErrorCode& status) {
- const number::LocalizedNumberFormatter* lnfBase = df->toNumberFormatter(status);
- if (U_FAILURE(status)) {
- return nullptr;
- }
- return lnfBase->integerWidth(
- number::IntegerWidth::zeroFillTo(minInt).truncateAt(maxInt)
- ).clone().orphan();
-}
-
-void SimpleDateFormat::initFastNumberFormatters(UErrorCode& status) {
+void
+SimpleDateFormat::initSimpleNumberFormatter(UErrorCode &status) {
if (U_FAILURE(status)) {
return;
}
if (df == nullptr) {
return;
}
- fFastNumberFormatters[SMPDTFMT_NF_1x10] = createFastFormatter(df, 1, 10, status);
- fFastNumberFormatters[SMPDTFMT_NF_2x10] = createFastFormatter(df, 2, 10, status);
- fFastNumberFormatters[SMPDTFMT_NF_3x10] = createFastFormatter(df, 3, 10, status);
- fFastNumberFormatters[SMPDTFMT_NF_4x10] = createFastFormatter(df, 4, 10, status);
- fFastNumberFormatters[SMPDTFMT_NF_2x2] = createFastFormatter(df, 2, 2, status);
-}
-
-void SimpleDateFormat::freeFastNumberFormatters() {
- delete fFastNumberFormatters[SMPDTFMT_NF_1x10];
- delete fFastNumberFormatters[SMPDTFMT_NF_2x10];
- delete fFastNumberFormatters[SMPDTFMT_NF_3x10];
- delete fFastNumberFormatters[SMPDTFMT_NF_4x10];
- delete fFastNumberFormatters[SMPDTFMT_NF_2x2];
- fFastNumberFormatters[SMPDTFMT_NF_1x10] = nullptr;
- fFastNumberFormatters[SMPDTFMT_NF_2x10] = nullptr;
- fFastNumberFormatters[SMPDTFMT_NF_3x10] = nullptr;
- fFastNumberFormatters[SMPDTFMT_NF_4x10] = nullptr;
- fFastNumberFormatters[SMPDTFMT_NF_2x2] = nullptr;
+ const DecimalFormatSymbols* syms = df->getDecimalFormatSymbols();
+ if (syms == nullptr) {
+ return;
+ }
+ fSimpleNumberFormatter = new number::SimpleNumberFormatter(
+ number::SimpleNumberFormatter::forLocaleAndSymbolsAndGroupingStrategy(
+ fLocale, *syms, UNUM_GROUPING_OFF, status
+ )
+ );
+ if (fSimpleNumberFormatter == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
}
-
void
SimpleDateFormat::initNumberFormatters(const Locale &locale,UErrorCode &status) {
if (U_FAILURE(status)) {
//----------------------------------------------------------------------
void SimpleDateFormat::adoptNumberFormat(NumberFormat *formatToAdopt) {
+ // Null out the fast formatter, it references fNumberFormat which we're
+ // about to invalidate
+ delete fSimpleNumberFormatter;
+ fSimpleNumberFormatter = nullptr;
+
fixNumberFormatForDates(*formatToAdopt);
delete fNumberFormat;
fNumberFormat = formatToAdopt;
fSharedNumberFormatters = NULL;
}
- // Also re-compute the fast formatters.
+ // Recompute fSimpleNumberFormatter if necessary
UErrorCode localStatus = U_ZERO_ERROR;
- freeFastNumberFormatters();
- initFastNumberFormatters(localStatus);
+ initSimpleNumberFormatter(localStatus);
}
void SimpleDateFormat::adoptNumberFormat(const UnicodeString& fields, NumberFormat *formatToAdopt, UErrorCode &status){
UnicodeString &appendTo,
int32_t value, int32_t minDigits, int32_t maxDigits) const
{
- const number::LocalizedNumberFormatter* fastFormatter = nullptr;
- // NOTE: This uses the heuristic that these five min/max int settings account for the vast majority
- // of SimpleDateFormat number formatting cases at the time of writing (ICU 62).
- if (currentNumberFormat == fNumberFormat) {
- if (maxDigits == 10) {
- if (minDigits == 1) {
- fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_1x10];
- } else if (minDigits == 2) {
- fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_2x10];
- } else if (minDigits == 3) {
- fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_3x10];
- } else if (minDigits == 4) {
- fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_4x10];
- }
- } else if (maxDigits == 2) {
- if (minDigits == 2) {
- fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_2x2];
- }
- }
- }
- if (fastFormatter != nullptr) {
+
+ if (currentNumberFormat == fNumberFormat && fSimpleNumberFormatter) {
// Can use fast path
- number::impl::UFormattedNumberData result;
- result.quantity.setToInt(value);
UErrorCode localStatus = U_ZERO_ERROR;
- fastFormatter->formatImpl(&result, localStatus);
+ number::SimpleNumber number = number::SimpleNumber::forInt64(value, localStatus);
+ number.setMinimumIntegerDigits(minDigits, localStatus);
+ number.truncateStart(maxDigits, localStatus);
+
+ number::FormattedNumber result = fSimpleNumberFormatter->format(std::move(number), localStatus);
if (U_FAILURE(localStatus)) {
return;
}
- appendTo.append(result.getStringRef().toTempUnicodeString());
+ appendTo.append(result.toTempString(localStatus));
return;
}
namespace number {
class LocalizedNumberFormatter;
+class SimpleNumberFormatter;
}
/**
int32_t skipUWhiteSpace(const UnicodeString& text, int32_t pos) const;
/**
- * Initialize LocalizedNumberFormatter instances used for speedup.
+ * Initialize SimpleNumberFormat instance
*/
- void initFastNumberFormatters(UErrorCode& status);
-
- /**
- * Delete the LocalizedNumberFormatter instances used for speedup.
- */
- void freeFastNumberFormatters();
+ void initSimpleNumberFormatter(UErrorCode &status);
/**
* Initialize NumberFormat instances used for numbering system overrides.
* A pointer to an object containing the strings to use in formatting (e.g.,
* month and day names, AM and PM strings, time zone names, etc.)
*/
- DateFormatSymbols* fSymbols; // Owned
+ DateFormatSymbols* fSymbols = nullptr; // Owned
/**
* The time zone formatter
*/
- TimeZoneFormat* fTimeZoneFormat;
+ TimeZoneFormat* fTimeZoneFormat = nullptr;
/**
* If dates have ambiguous years, we map them into the century starting
* The number format in use for each date field. NULL means fall back
* to fNumberFormat in DateFormat.
*/
- const SharedNumberFormat **fSharedNumberFormatters;
-
- enum NumberFormatterKey {
- SMPDTFMT_NF_1x10,
- SMPDTFMT_NF_2x10,
- SMPDTFMT_NF_3x10,
- SMPDTFMT_NF_4x10,
- SMPDTFMT_NF_2x2,
- SMPDTFMT_NF_COUNT
- };
+ const SharedNumberFormat **fSharedNumberFormatters = nullptr;
/**
- * Number formatters pre-allocated for fast performance on the most common integer lengths.
+ * Number formatter pre-allocated for fast performance
+ *
+ * This references the decimal symbols from fNumberFormatter if it is an instance
+ * of DecimalFormat (and is otherwise null). This should always be cleaned up before
+ * destroying fNumberFormatter.
*/
- const number::LocalizedNumberFormatter* fFastNumberFormatters[SMPDTFMT_NF_COUNT] = {};
+ const number::SimpleNumberFormatter* fSimpleNumberFormatter = nullptr;
UBool fHaveDefaultCentury;
- const BreakIterator* fCapitalizationBrkIter;
+ const BreakIterator* fCapitalizationBrkIter = nullptr;
};
inline UDate