mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-13 08:53:20 +00:00
ICU-2203 C++ version of NumberFormat registration
X-SVN-Rev: 11160
This commit is contained in:
parent
5bc8014e68
commit
c31688a777
7 changed files with 447 additions and 6 deletions
|
@ -767,6 +767,9 @@ public:
|
|||
}
|
||||
|
||||
void reset(UErrorCode& status) {
|
||||
if (status == U_ENUM_OUT_OF_SYNC_ERROR) {
|
||||
status = U_ZERO_ERROR;
|
||||
}
|
||||
if (U_SUCCESS(status)) {
|
||||
_timestamp = _service->getTimestamp();
|
||||
_pos = 0;
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "unicode/resbund.h"
|
||||
#include "unicode/dcfmtsym.h"
|
||||
#include "unicode/decimfmt.h"
|
||||
#include "iculserv.h"
|
||||
#include <float.h>
|
||||
|
||||
// If no number pattern can be located for a locale, this is the last
|
||||
|
@ -300,6 +301,155 @@ NumberFormat::getAvailableLocales(int32_t& count)
|
|||
return Locale::getAvailableLocales(count);
|
||||
}
|
||||
|
||||
// ------------------------------------------
|
||||
//
|
||||
// Registration
|
||||
//
|
||||
//-------------------------------------------
|
||||
|
||||
static ICULocaleService* gService = NULL;
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
class ICUNumberFormatFactory : public ICUResourceBundleFactory {
|
||||
protected:
|
||||
virtual UObject* handleCreate(const Locale& loc, int32_t kind, const ICUService* service, UErrorCode& status) const {
|
||||
// !!! kind is not an EStyles, need to determine how to handle this
|
||||
return NumberFormat::makeInstance(loc, (NumberFormat::EStyles)kind, status);
|
||||
}
|
||||
};
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
class NFFactory : public LocaleKeyFactory {
|
||||
private:
|
||||
NumberFormatFactory* _delegate;
|
||||
|
||||
public:
|
||||
NFFactory(NumberFormatFactory* delegate)
|
||||
: LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE)
|
||||
, _delegate(delegate)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~NFFactory()
|
||||
{
|
||||
delete _delegate;
|
||||
}
|
||||
|
||||
virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const
|
||||
{
|
||||
if (handlesKey(key, status)) {
|
||||
const LocaleKey& lkey = (const LocaleKey&)key;
|
||||
Locale loc;
|
||||
lkey.canonicalLocale(loc);
|
||||
int32_t kind = lkey.kind();
|
||||
|
||||
UObject* result = _delegate->createFormat(loc, (UNumberFormatStyle)(kind+1));
|
||||
if (result == NULL) {
|
||||
result = service->getKey((ICUServiceKey&)key /* cast away const */, NULL, this, status);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Return the set of ids that this factory supports (visible or
|
||||
* otherwise). This can be called often and might need to be
|
||||
* cached if it is expensive to create.
|
||||
*/
|
||||
virtual const Hashtable* getSupportedIDs(UErrorCode& status) const
|
||||
{
|
||||
return _delegate->getSupportedIDs(status);
|
||||
}
|
||||
};
|
||||
|
||||
class ICUNumberFormatService : public ICULocaleService {
|
||||
public:
|
||||
ICUNumberFormatService()
|
||||
: ICULocaleService("Number Format")
|
||||
{
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
registerFactory(new ICUNumberFormatFactory(), status);
|
||||
}
|
||||
|
||||
virtual UObject* cloneInstance(UObject* instance) const {
|
||||
return ((NumberFormat*)instance)->clone();
|
||||
}
|
||||
|
||||
virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* actualID, UErrorCode& status) const {
|
||||
LocaleKey& lkey = (LocaleKey&)key;
|
||||
int32_t kind = lkey.kind();
|
||||
Locale loc;
|
||||
lkey.currentLocale(loc);
|
||||
return NumberFormat::makeInstance(loc, (NumberFormat::EStyles)kind, status);
|
||||
}
|
||||
|
||||
virtual UBool isDefault() const {
|
||||
return countFactories() == 1;
|
||||
}
|
||||
};
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
static UMTX gLock = 0;
|
||||
|
||||
static ICULocaleService*
|
||||
getService(void)
|
||||
{
|
||||
if (gService == NULL) {
|
||||
Mutex mutex(&gLock);
|
||||
if (gService == NULL) {
|
||||
gService = new ICUNumberFormatService();
|
||||
}
|
||||
}
|
||||
return gService;
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
NumberFormat*
|
||||
NumberFormat::createInstance(const Locale& loc, EStyles kind, UErrorCode& status)
|
||||
{
|
||||
if (gService != NULL) {
|
||||
return (NumberFormat*)gService->get(loc, kind, status);
|
||||
} else {
|
||||
return makeInstance(loc, kind, status);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
URegistryKey
|
||||
NumberFormat::registerFactory(NumberFormatFactory* toAdopt, UErrorCode& status)
|
||||
{
|
||||
return getService()->registerFactory(new NFFactory(toAdopt), status);
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
UBool
|
||||
NumberFormat::unregister(URegistryKey key, UErrorCode& status)
|
||||
{
|
||||
if (U_SUCCESS(status)) {
|
||||
if (gService != NULL) {
|
||||
return gService->unregister(key, status);
|
||||
}
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
StringEnumeration*
|
||||
NumberFormat::getAvailableLocales(void)
|
||||
{
|
||||
return getService()->getAvailableLocales();
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
// Checks if the thousand/10 thousand grouping is used in the
|
||||
// NumberFormat instance.
|
||||
|
@ -412,9 +562,9 @@ NumberFormat::setMinimumFractionDigits(int32_t newValue)
|
|||
// or percent) for the desired locale.
|
||||
|
||||
NumberFormat*
|
||||
NumberFormat::createInstance(const Locale& desiredLocale,
|
||||
EStyles style,
|
||||
UErrorCode& status)
|
||||
NumberFormat::makeInstance(const Locale& desiredLocale,
|
||||
EStyles style,
|
||||
UErrorCode& status)
|
||||
{
|
||||
if (U_FAILURE(status)) return NULL;
|
||||
|
||||
|
@ -505,6 +655,20 @@ NumberFormat::createInstance(const Locale& desiredLocale,
|
|||
|
||||
U_NAMESPACE_END
|
||||
|
||||
// defined in ucln_cmn.h
|
||||
|
||||
/**
|
||||
* Release all static memory held by numberformat.
|
||||
*/
|
||||
U_CFUNC UBool numfmt_cleanup(void) {
|
||||
if (gService) {
|
||||
delete gService;
|
||||
gService = NULL;
|
||||
}
|
||||
umtx_destroy(&gLock);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
||||
//eof
|
||||
|
|
|
@ -25,6 +25,7 @@ static UBool i18n_cleanup(void)
|
|||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
timeZone_cleanup();
|
||||
numfmt_cleanup();
|
||||
#endif
|
||||
|
||||
#if !UCONFIG_NO_COLLATION
|
||||
|
|
|
@ -34,4 +34,6 @@ U_CFUNC UBool ucol_bld_cleanup(void);
|
|||
|
||||
U_CFUNC UBool regex_cleanup(void);
|
||||
|
||||
U_CFUNC UBool numfmt_cleanup(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -26,10 +26,16 @@
|
|||
|
||||
#include "unicode/unistr.h"
|
||||
#include "unicode/format.h"
|
||||
#include "unicode/unum.h" // UNumberFormatStyle
|
||||
#include "hash.h"
|
||||
#include "unicode/locid.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
class Locale;
|
||||
class NumberFormatFactory;
|
||||
class StringEnumeration;
|
||||
|
||||
typedef const void* URegistryKey;
|
||||
|
||||
/**
|
||||
* Abstract base class for all number formats. Provides interface for
|
||||
|
@ -420,6 +426,34 @@ public:
|
|||
*/
|
||||
static const Locale* getAvailableLocales(int32_t& count);
|
||||
|
||||
/**
|
||||
* Register a new NumberFormatFactory. The factory will be adopted.
|
||||
* @param toAdopt the NumberFormatFactory instance to be adopted
|
||||
* @param status the in/out status code, no special meanings are assigned
|
||||
* @return a registry key that can be used to unregister this factory
|
||||
* @draft ICU 2.6
|
||||
*/
|
||||
static URegistryKey registerFactory(NumberFormatFactory* toAdopt, UErrorCode& status);
|
||||
|
||||
/**
|
||||
* Unregister a previously-registered NumberFormatFactory using the key returned from the
|
||||
* register call. Key becomes invalid after a successful call and should not be used again.
|
||||
* The NumberFormatFactory corresponding to the key will be deleted.
|
||||
* @param key the registry key returned by a previous call to registerFactory
|
||||
* @param status the in/out status code, no special meanings are assigned
|
||||
* @return TRUE if the factory for the key was successfully unregistered
|
||||
* @draft ICU 2.6
|
||||
*/
|
||||
static UBool unregister(URegistryKey key, UErrorCode& status);
|
||||
|
||||
/**
|
||||
* Return a StringEnumeration over the locales available at the time of the call,
|
||||
* including registered locales.
|
||||
* @return a StringEnumeration over the locales available at the time of the call
|
||||
* @draft ICU 2.6
|
||||
*/
|
||||
static StringEnumeration* getAvailableLocales(void);
|
||||
|
||||
/**
|
||||
* Returns true if grouping is used in this format. For example,
|
||||
* in the English locale, with grouping on, the number 1234567
|
||||
|
@ -545,7 +579,6 @@ public:
|
|||
static inline UClassID getStaticClassID(void);
|
||||
|
||||
/**
|
||||
* Override Calendar
|
||||
* Returns a unique class ID POLYMORPHICALLY. Pure virtual override.
|
||||
* This method is to implement a simple version of RTTI, since not all
|
||||
* C++ compilers support genuine RTTI. Polymorphic operator==() and
|
||||
|
@ -595,6 +628,8 @@ private:
|
|||
|
||||
/**
|
||||
* Creates the specified decimal format style of the desired locale.
|
||||
* Hook for service registration, uses makeInstance directly if no services
|
||||
* registered.
|
||||
* @param desiredLocale the given locale.
|
||||
* @param choice the given style.
|
||||
* @param success Output param filled with success/failure status.
|
||||
|
@ -602,6 +637,14 @@ private:
|
|||
*/
|
||||
static NumberFormat* createInstance(const Locale& desiredLocale, EStyles choice, UErrorCode& success);
|
||||
|
||||
/**
|
||||
* Creates the specified decimal format style of the desired locale.
|
||||
* @param desiredLocale the given locale.
|
||||
* @param choice the given style.
|
||||
* @param success Output param filled with success/failure status.
|
||||
* @return A new NumberFormat instance.
|
||||
*/
|
||||
static NumberFormat* makeInstance(const Locale& desiredLocale, EStyles choice, UErrorCode& success);
|
||||
static const int32_t fgNumberPatternsCount;
|
||||
static const UChar* const fgLastResortNumberPatterns[];
|
||||
|
||||
|
@ -611,8 +654,75 @@ private:
|
|||
int32_t fMaxFractionDigits;
|
||||
int32_t fMinFractionDigits;
|
||||
UBool fParseIntegerOnly;
|
||||
|
||||
friend class ICUNumberFormatFactory; // access to makeInstance, EStyles
|
||||
friend class ICUNumberFormatService;
|
||||
};
|
||||
|
||||
/**
|
||||
* A NumberFormatFactory is used to register new number formats. The factory
|
||||
* should be able to create any of the predefined formats for each locale it
|
||||
* supports. When registered, the locales it supports extend or override the
|
||||
* locale already supported by ICU.
|
||||
*
|
||||
* @prototype
|
||||
*/
|
||||
class U_I18N_API NumberFormatFactory : public UObject {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Return true if this factory will be visible. Default is true.
|
||||
* If not visible, the locales supported by this factory will not
|
||||
* be listed by getAvailableLocales.
|
||||
*/
|
||||
virtual UBool visible(void) const = 0;
|
||||
|
||||
/**
|
||||
* Return an unmodifiable collection of the locale names directly
|
||||
* supported by this factory.
|
||||
*/
|
||||
virtual const Hashtable* getSupportedIDs(UErrorCode& status) const = 0;
|
||||
|
||||
/**
|
||||
* Return a number format of the appropriate type. If the locale
|
||||
* is not supported, return null. If the locale is supported, but
|
||||
* the type is not provided by this service, return null. Otherwise
|
||||
* return an appropriate instance of NumberFormat.
|
||||
*/
|
||||
virtual NumberFormat* createFormat(const Locale& loc, UNumberFormatStyle formatType) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* A NumberFormatFactory that supports a single locale. It can be visible or invisible.
|
||||
* @prototype
|
||||
*/
|
||||
class U_I18N_API SimpleNumberFormatFactory : public NumberFormatFactory {
|
||||
protected:
|
||||
const UBool _visible;
|
||||
Hashtable _ids;
|
||||
|
||||
public:
|
||||
SimpleNumberFormatFactory(const Locale& locale, UBool visible = TRUE)
|
||||
: _visible(visible)
|
||||
{
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
_ids.put(locale.getName(), this, status); // um, ignore error code...
|
||||
}
|
||||
|
||||
virtual UBool visible(void) const {
|
||||
return _visible;
|
||||
}
|
||||
|
||||
virtual const Hashtable* getSupportedIDs(UErrorCode& status) const
|
||||
{
|
||||
if (U_SUCCESS(status)) {
|
||||
return &_ids;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
inline UClassID
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#include "unicode/numfmt.h"
|
||||
#include "unicode/decimfmt.h"
|
||||
#include "unicode/locid.h"
|
||||
#include "unicode/unum.h"
|
||||
#include "unicode/strenum.h"
|
||||
|
||||
// This is an API test, not a unit test. It doesn't test very many cases, and doesn't
|
||||
// try to test the full functionality. It just calls each function in the class and
|
||||
|
@ -33,7 +35,17 @@ void IntlTestNumberFormatAPI::runIndexedTest( int32_t index, UBool exec, const c
|
|||
testAPI(/* par */);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: name = "NumberFormatRegistration";
|
||||
if (exec) {
|
||||
logln("NumberFormat Registration test---"); logln("");
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
Locale::setDefault(Locale::getEnglish(), status);
|
||||
if(U_FAILURE(status)) {
|
||||
errln("ERROR: Could not set default locale, test may not give correct results");
|
||||
}
|
||||
testRegistration();
|
||||
}
|
||||
break;
|
||||
default: name = ""; break;
|
||||
}
|
||||
}
|
||||
|
@ -226,4 +238,152 @@ void IntlTestNumberFormatAPI::testAPI(/* char* par */)
|
|||
delete per_fr;
|
||||
}
|
||||
|
||||
#define SRC_LOC Locale::getFrance()
|
||||
#define SWAP_LOC Locale::getUS()
|
||||
|
||||
class TestFactory : public SimpleNumberFormatFactory {
|
||||
NumberFormat* currencyStyle;
|
||||
|
||||
public:
|
||||
TestFactory()
|
||||
: SimpleNumberFormatFactory(SRC_LOC, TRUE)
|
||||
{
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
currencyStyle = NumberFormat::createInstance(SWAP_LOC, status);
|
||||
}
|
||||
|
||||
virtual ~TestFactory()
|
||||
{
|
||||
delete currencyStyle;
|
||||
}
|
||||
|
||||
virtual NumberFormat* createFormat(const Locale& loc, UNumberFormatStyle formatType)
|
||||
{
|
||||
if (formatType == UNUM_CURRENCY) {
|
||||
return (NumberFormat*)currencyStyle->clone();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virtual inline UClassID getDynamicClassID() const
|
||||
{
|
||||
return (UClassID)gID;
|
||||
}
|
||||
|
||||
static inline UClassID getStaticClassID()
|
||||
{
|
||||
return (UClassID)gID;
|
||||
}
|
||||
|
||||
private:
|
||||
static char gID;
|
||||
};
|
||||
|
||||
char TestFactory::gID = 0;
|
||||
|
||||
void
|
||||
IntlTestNumberFormatAPI::testRegistration()
|
||||
{
|
||||
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
|
||||
NumberFormat* f0 = NumberFormat::createInstance(SWAP_LOC, status);
|
||||
NumberFormat* f1 = NumberFormat::createInstance(SRC_LOC, status);
|
||||
NumberFormat* f2 = NumberFormat::createCurrencyInstance(SRC_LOC, status);
|
||||
URegistryKey key = NumberFormat::registerFactory(new TestFactory(), status);
|
||||
NumberFormat* f3 = NumberFormat::createCurrencyInstance(SRC_LOC, status);
|
||||
NumberFormat* f3a = NumberFormat::createCurrencyInstance(SRC_LOC, status);
|
||||
NumberFormat* f4 = NumberFormat::createInstance(SRC_LOC, status);
|
||||
|
||||
StringEnumeration* locs = NumberFormat::getAvailableLocales();
|
||||
|
||||
UNumberFormat* uf3 = unum_open(UNUM_CURRENCY, NULL, 0, SRC_LOC.getName(),NULL, &status);
|
||||
UNumberFormat* uf4 = unum_open(UNUM_DEFAULT, NULL, 0, SRC_LOC.getName(), NULL, &status);
|
||||
|
||||
for (const UnicodeString* res = locs->snext(status); res; res = locs->snext(status)) {
|
||||
logln(*res); // service is still in synch
|
||||
}
|
||||
|
||||
NumberFormat::unregister(key, status); // restore for other tests
|
||||
NumberFormat* f5 = NumberFormat::createCurrencyInstance(SRC_LOC, status);
|
||||
UNumberFormat* uf5 = unum_open(UNUM_CURRENCY, NULL, 0, SRC_LOC.getName(),NULL, &status);
|
||||
|
||||
float n = 1234.567f;
|
||||
UnicodeString res0, res1, res2, res3, res4, res5;
|
||||
UChar ures3[50];
|
||||
UChar ures4[50];
|
||||
UChar ures5[50];
|
||||
|
||||
f0->format(n, res0);
|
||||
f1->format(n, res1);
|
||||
f2->format(n, res2);
|
||||
f3->format(n, res3);
|
||||
f4->format(n, res4);
|
||||
f5->format(n, res5);
|
||||
|
||||
unum_formatDouble(uf3, n, ures3, 50, NULL, &status);
|
||||
unum_formatDouble(uf4, n, ures4, 50, NULL, &status);
|
||||
unum_formatDouble(uf5, n, ures5, 50, NULL, &status);
|
||||
|
||||
logln((UnicodeString)"f0 swap int: " + res0);
|
||||
logln((UnicodeString)"f1 src int: " + res1);
|
||||
logln((UnicodeString)"f2 src cur: " + res2);
|
||||
logln((UnicodeString)"f3 reg cur: " + res3);
|
||||
logln((UnicodeString)"f4 reg int: " + res4);
|
||||
logln((UnicodeString)"f5 unreg cur: " + res5);
|
||||
log("uf3 reg cur: ");
|
||||
logln(ures3);
|
||||
log("uf4 reg int: ");
|
||||
logln(ures4);
|
||||
log("uf5 ureg cur: ");
|
||||
logln(ures5);
|
||||
|
||||
if (f3 == f3a) {
|
||||
errln("did not get new instance from service");
|
||||
} else {
|
||||
delete f3a;
|
||||
}
|
||||
if (res3 != res0) {
|
||||
errln("registered service did not match");
|
||||
}
|
||||
if (res4 != res1) {
|
||||
errln("registered service did not inherit");
|
||||
}
|
||||
if (res5 != res2) {
|
||||
errln("unregistered service did not match original");
|
||||
}
|
||||
|
||||
if (res0 != ures3) {
|
||||
errln("registered service did not match / unum");
|
||||
}
|
||||
if (res1 != ures4) {
|
||||
errln("registered service did not inherit / unum");
|
||||
}
|
||||
if (res2 != ures5) {
|
||||
errln("unregistered service did not match original / unum");
|
||||
}
|
||||
|
||||
unum_close(uf5);
|
||||
delete f5;
|
||||
unum_close(uf4);
|
||||
unum_close(uf3);
|
||||
delete f4;
|
||||
delete f3;
|
||||
delete f2;
|
||||
delete f1;
|
||||
delete f0;
|
||||
|
||||
for (const UnicodeString* res = locs->snext(status); res; res = locs->snext(status)) {
|
||||
errln(*res); // service should be out of synch
|
||||
}
|
||||
|
||||
locs->reset(status); // now in synch again, we hope
|
||||
for (const UnicodeString* res = locs->snext(status); res; res = locs->snext(status)) {
|
||||
logln(*res);
|
||||
}
|
||||
|
||||
delete locs;
|
||||
}
|
||||
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
|
|
@ -25,6 +25,7 @@ private:
|
|||
* executes tests of API functions, see detailed comments in source code
|
||||
**/
|
||||
void testAPI(/* char* par */);
|
||||
void testRegistration();
|
||||
};
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
|
Loading…
Add table
Reference in a new issue