BNumberFormat: cache ICU formatters

For performance reasons, it is a good idea to keep the formatters
instanciated, instead of re-creating them each time we need to format a
number.
This commit is contained in:
Adrien Destugues
2017-07-23 10:24:02 +02:00
parent 0e4ad75e47
commit 6cbcfc1911
2 changed files with 131 additions and 48 deletions
+15 -14
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2003-2014, Haiku, Inc. * Copyright 2003-2017, Haiku, Inc.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef _B_NUMBER_FORMAT_H_ #ifndef _B_NUMBER_FORMAT_H_
@@ -16,30 +16,31 @@ enum BNumberElement {
B_NUMBER_ELEMENT_CURRENCY B_NUMBER_ELEMENT_CURRENCY
}; };
class BNumberFormatImpl;
class BNumberFormat : public BFormat { class BNumberFormat : public BFormat {
public: public:
BNumberFormat(); BNumberFormat();
BNumberFormat(const BNumberFormat &other);
~BNumberFormat(); ~BNumberFormat();
// formatting
ssize_t Format(char* string, size_t maxSize, ssize_t Format(char* string, size_t maxSize,
const double value) const; const double value);
status_t Format(BString& string, const double value) status_t Format(BString& string, const double value);
const;
ssize_t Format(char* string, size_t maxSize, ssize_t Format(char* string, size_t maxSize,
const int32 value) const; const int32 value);
status_t Format(BString& string, const int32 value) status_t Format(BString& string, const int32 value);
const;
// monetary
ssize_t FormatMonetary(char* string, size_t maxSize, ssize_t FormatMonetary(char* string, size_t maxSize,
const double value) const; const double value);
status_t FormatMonetary(BString& string, status_t FormatMonetary(BString& string,
const double value) const; const double value);
private:
BNumberFormat(const BNumberFormat &other);
private:
BNumberFormatImpl* fPrivateData;
}; };
+116 -34
View File
@@ -18,20 +18,122 @@
#include <unicode/numfmt.h> #include <unicode/numfmt.h>
class BNumberFormatImpl {
public:
BNumberFormatImpl();
~BNumberFormatImpl();
NumberFormat* GetInteger(BFormattingConventions* convention);
NumberFormat* GetFloat(BFormattingConventions* convention);
NumberFormat* GetCurrency(BFormattingConventions* convention);
private:
NumberFormat* fIntegerFormat;
NumberFormat* fFloatFormat;
NumberFormat* fCurrencyFormat;
};
BNumberFormatImpl::BNumberFormatImpl()
{
// They are initialized lazily as needed
fIntegerFormat = NULL;
fFloatFormat = NULL;
fCurrencyFormat = NULL;
}
BNumberFormatImpl::~BNumberFormatImpl()
{
delete fIntegerFormat;
delete fFloatFormat;
delete fCurrencyFormat;
}
NumberFormat*
BNumberFormatImpl::GetInteger(BFormattingConventions* convention)
{
if (fIntegerFormat == NULL) {
UErrorCode err = U_ZERO_ERROR;
fIntegerFormat = NumberFormat::createInstance(
*BFormattingConventions::Private(convention).ICULocale(),
UNUM_DECIMAL, err);
if (fIntegerFormat == NULL)
return NULL;
if (U_FAILURE(err)) {
delete fIntegerFormat;
fIntegerFormat = NULL;
return NULL;
}
}
return fIntegerFormat;
}
NumberFormat*
BNumberFormatImpl::GetFloat(BFormattingConventions* convention)
{
if (fFloatFormat == NULL) {
UErrorCode err = U_ZERO_ERROR;
fFloatFormat = NumberFormat::createInstance(
*BFormattingConventions::Private(convention).ICULocale(),
UNUM_DECIMAL, err);
if (fFloatFormat == NULL)
return NULL;
if (U_FAILURE(err)) {
delete fFloatFormat;
fFloatFormat = NULL;
return NULL;
}
}
return fFloatFormat;
}
NumberFormat*
BNumberFormatImpl::GetCurrency(BFormattingConventions* convention)
{
if (fCurrencyFormat == NULL) {
UErrorCode err = U_ZERO_ERROR;
fCurrencyFormat = NumberFormat::createCurrencyInstance(
*BFormattingConventions::Private(convention).ICULocale(),
err);
if (fCurrencyFormat == NULL)
return NULL;
if (U_FAILURE(err)) {
delete fCurrencyFormat;
fCurrencyFormat = NULL;
return NULL;
}
}
return fCurrencyFormat;
}
BNumberFormat::BNumberFormat() BNumberFormat::BNumberFormat()
: BFormat() : BFormat()
{ {
fPrivateData = new BNumberFormatImpl();
} }
BNumberFormat::BNumberFormat(const BNumberFormat &other) BNumberFormat::BNumberFormat(const BNumberFormat &other)
: BFormat(other) : BFormat(other)
{ {
fPrivateData = new BNumberFormatImpl(*other.fPrivateData);
} }
BNumberFormat::~BNumberFormat() BNumberFormat::~BNumberFormat()
{ {
delete fPrivateData;
} }
@@ -39,7 +141,7 @@ BNumberFormat::~BNumberFormat()
ssize_t ssize_t
BNumberFormat::Format(char* string, size_t maxSize, const double value) const BNumberFormat::Format(char* string, size_t maxSize, const double value)
{ {
BString fullString; BString fullString;
status_t status = Format(fullString, value); status_t status = Format(fullString, value);
@@ -51,20 +153,15 @@ BNumberFormat::Format(char* string, size_t maxSize, const double value) const
status_t status_t
BNumberFormat::Format(BString& string, const double value) const BNumberFormat::Format(BString& string, const double value)
{ {
UErrorCode err = U_ZERO_ERROR; NumberFormat* formatter = fPrivateData->GetFloat(&fConventions);
ObjectDeleter<NumberFormat> numberFormatter(NumberFormat::createInstance(
*BFormattingConventions::Private(&fConventions).ICULocale(),
UNUM_DECIMAL, err));
if (numberFormatter.Get() == NULL) if (formatter == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
if (U_FAILURE(err))
return B_BAD_VALUE;
UnicodeString icuString; UnicodeString icuString;
numberFormatter->format(value, icuString); formatter->format(value, icuString);
string.Truncate(0); string.Truncate(0);
BStringByteSink stringConverter(&string); BStringByteSink stringConverter(&string);
@@ -75,7 +172,7 @@ BNumberFormat::Format(BString& string, const double value) const
ssize_t ssize_t
BNumberFormat::Format(char* string, size_t maxSize, const int32 value) const BNumberFormat::Format(char* string, size_t maxSize, const int32 value)
{ {
BString fullString; BString fullString;
status_t status = Format(fullString, value); status_t status = Format(fullString, value);
@@ -87,20 +184,15 @@ BNumberFormat::Format(char* string, size_t maxSize, const int32 value) const
status_t status_t
BNumberFormat::Format(BString& string, const int32 value) const BNumberFormat::Format(BString& string, const int32 value)
{ {
UErrorCode err = U_ZERO_ERROR; NumberFormat* formatter = fPrivateData->GetInteger(&fConventions);
ObjectDeleter<NumberFormat> numberFormatter(NumberFormat::createInstance(
*BFormattingConventions::Private(&fConventions).ICULocale(),
UNUM_DECIMAL, err));
if (numberFormatter.Get() == NULL) if (formatter == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
if (U_FAILURE(err))
return B_BAD_VALUE;
UnicodeString icuString; UnicodeString icuString;
numberFormatter->format((int32_t)value, icuString); formatter->format((int32_t)value, icuString);
string.Truncate(0); string.Truncate(0);
BStringByteSink stringConverter(&string); BStringByteSink stringConverter(&string);
@@ -112,7 +204,6 @@ BNumberFormat::Format(BString& string, const int32 value) const
ssize_t ssize_t
BNumberFormat::FormatMonetary(char* string, size_t maxSize, const double value) BNumberFormat::FormatMonetary(char* string, size_t maxSize, const double value)
const
{ {
BString fullString; BString fullString;
status_t status = FormatMonetary(fullString, value); status_t status = FormatMonetary(fullString, value);
@@ -124,24 +215,15 @@ BNumberFormat::FormatMonetary(char* string, size_t maxSize, const double value)
status_t status_t
BNumberFormat::FormatMonetary(BString& string, const double value) const BNumberFormat::FormatMonetary(BString& string, const double value)
{ {
if (string == NULL) NumberFormat* formatter = fPrivateData->GetCurrency(&fConventions);
return B_BAD_VALUE;
UErrorCode err = U_ZERO_ERROR; if (formatter == NULL)
ObjectDeleter<NumberFormat> numberFormatter(
NumberFormat::createCurrencyInstance(
*BFormattingConventions::Private(&fConventions).ICULocale(),
err));
if (numberFormatter.Get() == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
if (U_FAILURE(err))
return B_BAD_VALUE;
UnicodeString icuString; UnicodeString icuString;
numberFormatter->format(value, icuString); formatter->format(value, icuString);
string.Truncate(0); string.Truncate(0);
BStringByteSink stringConverter(&string); BStringByteSink stringConverter(&string);