|  | // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "base/i18n/number_formatting.h" | 
|  |  | 
|  | #include <stddef.h> | 
|  |  | 
|  | #include <memory> | 
|  |  | 
|  | #include "base/format_macros.h" | 
|  | #include "base/i18n/message_formatter.h" | 
|  | #include "base/i18n/unicodestring.h" | 
|  | #include "base/lazy_instance.h" | 
|  | #include "base/logging.h" | 
|  | #include "base/strings/string_util.h" | 
|  | #include "base/strings/stringprintf.h" | 
|  | #include "base/strings/utf_string_conversions.h" | 
|  | #include "third_party/icu/source/common/unicode/ustring.h" | 
|  | #include "third_party/icu/source/i18n/unicode/numfmt.h" | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // A simple wrapper around icu::NumberFormat that allows for resetting it | 
|  | // (as LazyInstance does not). | 
|  | struct NumberFormatWrapper { | 
|  | NumberFormatWrapper() { | 
|  | Reset(); | 
|  | } | 
|  |  | 
|  | void Reset() { | 
|  | // There's no ICU call to destroy a NumberFormat object other than | 
|  | // operator delete, so use the default Delete, which calls operator delete. | 
|  | // This can cause problems if a different allocator is used by this file | 
|  | // than by ICU. | 
|  | UErrorCode status = U_ZERO_ERROR; | 
|  | number_format.reset(icu::NumberFormat::createInstance(status)); | 
|  | DCHECK(U_SUCCESS(status)); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<icu::NumberFormat> number_format; | 
|  | }; | 
|  |  | 
|  | LazyInstance<NumberFormatWrapper>::DestructorAtExit g_number_format_int = | 
|  | LAZY_INSTANCE_INITIALIZER; | 
|  | LazyInstance<NumberFormatWrapper>::DestructorAtExit g_number_format_float = | 
|  | LAZY_INSTANCE_INITIALIZER; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | string16 FormatNumber(int64_t number) { | 
|  | icu::NumberFormat* number_format = | 
|  | g_number_format_int.Get().number_format.get(); | 
|  |  | 
|  | if (!number_format) { | 
|  | // As a fallback, just return the raw number in a string. | 
|  | return ASCIIToUTF16(StringPrintf("%" PRId64, number)); | 
|  | } | 
|  | icu::UnicodeString ustr; | 
|  | number_format->format(number, ustr); | 
|  |  | 
|  | return i18n::UnicodeStringToString16(ustr); | 
|  | } | 
|  |  | 
|  | string16 FormatDouble(double number, int fractional_digits) { | 
|  | icu::NumberFormat* number_format = | 
|  | g_number_format_float.Get().number_format.get(); | 
|  |  | 
|  | if (!number_format) { | 
|  | // As a fallback, just return the raw number in a string. | 
|  | return ASCIIToUTF16(StringPrintf("%f", number)); | 
|  | } | 
|  | number_format->setMaximumFractionDigits(fractional_digits); | 
|  | number_format->setMinimumFractionDigits(fractional_digits); | 
|  | icu::UnicodeString ustr; | 
|  | number_format->format(number, ustr); | 
|  |  | 
|  | return i18n::UnicodeStringToString16(ustr); | 
|  | } | 
|  |  | 
|  | string16 FormatPercent(int number) { | 
|  | return i18n::MessageFormatter::FormatWithNumberedArgs( | 
|  | ASCIIToUTF16("{0,number,percent}"), static_cast<double>(number) / 100.0); | 
|  | } | 
|  |  | 
|  | namespace testing { | 
|  |  | 
|  | void ResetFormatters() { | 
|  | g_number_format_int.Get().Reset(); | 
|  | g_number_format_float.Get().Reset(); | 
|  | } | 
|  |  | 
|  | }  // namespace testing | 
|  |  | 
|  | }  // namespace base |