X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/73c04bcfe1096173b00431f0cdc742894b15eef0..51004dcb01e06fef634b61be77ed73dd61cb6db9:/icuSources/common/serv.cpp diff --git a/icuSources/common/serv.cpp b/icuSources/common/serv.cpp index c00b9c8f..1a8c9166 100644 --- a/icuSources/common/serv.cpp +++ b/icuSources/common/serv.cpp @@ -1,9 +1,9 @@ - /** - ******************************************************************************* - * Copyright (C) 2001-2004, International Business Machines Corporation. * - * All Rights Reserved. * - ******************************************************************************* - */ +/** +******************************************************************************* +* Copyright (C) 2001-2012, International Business Machines Corporation. +* All Rights Reserved. +******************************************************************************* +*/ #include "unicode/utypes.h" @@ -19,13 +19,13 @@ U_NAMESPACE_BEGIN /* - ****************************************************************** - */ +****************************************************************** +*/ const UChar ICUServiceKey::PREFIX_DELIMITER = 0x002F; /* '/' */ ICUServiceKey::ICUServiceKey(const UnicodeString& id) - : _id(id) { +: _id(id) { } ICUServiceKey::~ICUServiceKey() @@ -35,355 +35,356 @@ ICUServiceKey::~ICUServiceKey() const UnicodeString& ICUServiceKey::getID() const { - return _id; + return _id; } UnicodeString& ICUServiceKey::canonicalID(UnicodeString& result) const { - return result.append(_id); + return result.append(_id); } UnicodeString& ICUServiceKey::currentID(UnicodeString& result) const { - return canonicalID(result); + return canonicalID(result); } UnicodeString& ICUServiceKey::currentDescriptor(UnicodeString& result) const { - prefix(result); - result.append(PREFIX_DELIMITER); - return currentID(result); + prefix(result); + result.append(PREFIX_DELIMITER); + return currentID(result); } UBool ICUServiceKey::fallback() { - return FALSE; + return FALSE; } UBool ICUServiceKey::isFallbackOf(const UnicodeString& id) const { - return id == _id; + return id == _id; } UnicodeString& ICUServiceKey::prefix(UnicodeString& result) const { - return result; + return result; } UnicodeString& ICUServiceKey::parsePrefix(UnicodeString& result) { - int32_t n = result.indexOf(PREFIX_DELIMITER); - if (n < 0) { - n = 0; - } - result.remove(n); - return result; + int32_t n = result.indexOf(PREFIX_DELIMITER); + if (n < 0) { + n = 0; + } + result.remove(n); + return result; } UnicodeString& ICUServiceKey::parseSuffix(UnicodeString& result) { - int32_t n = result.indexOf(PREFIX_DELIMITER); - if (n >= 0) { - result.remove(0, n+1); - } - return result; + int32_t n = result.indexOf(PREFIX_DELIMITER); + if (n >= 0) { + result.remove(0, n+1); + } + return result; } #ifdef SERVICE_DEBUG UnicodeString& ICUServiceKey::debug(UnicodeString& result) const { - debugClass(result); - result.append(" id: "); - result.append(_id); - return result; + debugClass(result); + result.append(" id: "); + result.append(_id); + return result; } UnicodeString& ICUServiceKey::debugClass(UnicodeString& result) const { - return result.append("ICUServiceKey"); + return result.append("ICUServiceKey"); } #endif UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ICUServiceKey) /* - ****************************************************************** - */ +****************************************************************** +*/ + +ICUServiceFactory::~ICUServiceFactory() {} SimpleFactory::SimpleFactory(UObject* instanceToAdopt, const UnicodeString& id, UBool visible) - : _instance(instanceToAdopt), _id(id), _visible(visible) +: _instance(instanceToAdopt), _id(id), _visible(visible) { } SimpleFactory::~SimpleFactory() { - delete _instance; + delete _instance; } UObject* SimpleFactory::create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const { - if (U_SUCCESS(status)) { - UnicodeString temp; - if (_id == key.currentID(temp)) { - return service->cloneInstance(_instance); + if (U_SUCCESS(status)) { + UnicodeString temp; + if (_id == key.currentID(temp)) { + return service->cloneInstance(_instance); + } } - } - return NULL; + return NULL; } void SimpleFactory::updateVisibleIDs(Hashtable& result, UErrorCode& status) const { - if (_visible) { - result.put(_id, (void*)this, status); // cast away const - } else { - result.remove(_id); - } + if (_visible) { + result.put(_id, (void*)this, status); // cast away const + } else { + result.remove(_id); + } } UnicodeString& SimpleFactory::getDisplayName(const UnicodeString& id, const Locale& /* locale */, UnicodeString& result) const { - if (_visible && _id == id) { - result = _id; - } else { - result.setToBogus(); - } - return result; + if (_visible && _id == id) { + result = _id; + } else { + result.setToBogus(); + } + return result; } #ifdef SERVICE_DEBUG UnicodeString& SimpleFactory::debug(UnicodeString& toAppendTo) const { - debugClass(toAppendTo); - toAppendTo.append(" id: "); - toAppendTo.append(_id); - toAppendTo.append(", visible: "); - toAppendTo.append(_visible ? "T" : "F"); - return toAppendTo; + debugClass(toAppendTo); + toAppendTo.append(" id: "); + toAppendTo.append(_id); + toAppendTo.append(", visible: "); + toAppendTo.append(_visible ? "T" : "F"); + return toAppendTo; } UnicodeString& SimpleFactory::debugClass(UnicodeString& toAppendTo) const { - return toAppendTo.append("SimpleFactory"); + return toAppendTo.append("SimpleFactory"); } #endif UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleFactory) /* - ****************************************************************** - */ +****************************************************************** +*/ + +ServiceListener::~ServiceListener() {} UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ServiceListener) /* - ****************************************************************** - */ +****************************************************************** +*/ - // Record the actual id for this service in the cache, so we can return it - // even if we succeed later with a different id. +// Record the actual id for this service in the cache, so we can return it +// even if we succeed later with a different id. class CacheEntry : public UMemory { private: - int32_t refcount; + int32_t refcount; public: - UnicodeString actualDescriptor; - UObject* service; - - /** - * Releases a reference to the shared resource. - */ - ~CacheEntry() { - delete service; - } - - CacheEntry(const UnicodeString& _actualDescriptor, UObject* _service) - : refcount(1), actualDescriptor(_actualDescriptor), service(_service) { - } - - /** - * Instantiation creates an initial reference, so don't call this - * unless you're creating a new pointer to this. Management of - * that pointer will have to know how to deal with refcounts. - * Return true if the resource has not already been released. - */ - CacheEntry* ref() { - ++refcount; - return this; - } - - /** - * Destructions removes a reference, so don't call this unless - * you're removing pointer to this somewhere. Management of that - * pointer will have to know how to deal with refcounts. Once - * the refcount drops to zero, the resource is released. Return - * false if the resouce has been released. - */ - CacheEntry* unref() { - if ((--refcount) == 0) { - delete this; - return NULL; - } - return this; - } - - /** - * Return TRUE if there is at least one reference to this and the - * resource has not been released. - */ - UBool isShared() const { - return refcount > 1; - } + UnicodeString actualDescriptor; + UObject* service; + + /** + * Releases a reference to the shared resource. + */ + ~CacheEntry() { + delete service; + } + + CacheEntry(const UnicodeString& _actualDescriptor, UObject* _service) + : refcount(1), actualDescriptor(_actualDescriptor), service(_service) { + } + + /** + * Instantiation creates an initial reference, so don't call this + * unless you're creating a new pointer to this. Management of + * that pointer will have to know how to deal with refcounts. + * Return true if the resource has not already been released. + */ + CacheEntry* ref() { + ++refcount; + return this; + } + + /** + * Destructions removes a reference, so don't call this unless + * you're removing pointer to this somewhere. Management of that + * pointer will have to know how to deal with refcounts. Once + * the refcount drops to zero, the resource is released. Return + * false if the resouce has been released. + */ + CacheEntry* unref() { + if ((--refcount) == 0) { + delete this; + return NULL; + } + return this; + } + + /** + * Return TRUE if there is at least one reference to this and the + * resource has not been released. + */ + UBool isShared() const { + return refcount > 1; + } }; // UObjectDeleter for serviceCache U_CDECL_BEGIN static void U_CALLCONV cacheDeleter(void* obj) { - U_NAMESPACE_USE - ((CacheEntry*)obj)->unref(); + U_NAMESPACE_USE ((CacheEntry*)obj)->unref(); } /** - * Deleter for UObjects - */ +* Deleter for UObjects +*/ static void U_CALLCONV deleteUObject(void *obj) { - U_NAMESPACE_USE - delete (UObject*) obj; + U_NAMESPACE_USE delete (UObject*) obj; } U_CDECL_END /* - ****************************************************************** - */ +****************************************************************** +*/ class DNCache : public UMemory { public: - Hashtable cache; - const Locale locale; - - DNCache(const Locale& _locale) - : cache(), locale(_locale) - { - // cache.setKeyDeleter(uhash_deleteUnicodeString); - } + Hashtable cache; + const Locale locale; + + DNCache(const Locale& _locale) + : cache(), locale(_locale) + { + // cache.setKeyDeleter(uprv_deleteUObject); + } }; /* - ****************************************************************** - */ +****************************************************************** +*/ StringPair* StringPair::create(const UnicodeString& displayName, const UnicodeString& id, UErrorCode& status) { - if (U_SUCCESS(status)) { - StringPair* sp = new StringPair(displayName, id); - if (sp == NULL || sp->isBogus()) { - status = U_MEMORY_ALLOCATION_ERROR; - delete sp; - return NULL; + if (U_SUCCESS(status)) { + StringPair* sp = new StringPair(displayName, id); + if (sp == NULL || sp->isBogus()) { + status = U_MEMORY_ALLOCATION_ERROR; + delete sp; + return NULL; + } + return sp; } - return sp; - } - return NULL; + return NULL; } UBool StringPair::isBogus() const { - return displayName.isBogus() || id.isBogus(); + return displayName.isBogus() || id.isBogus(); } StringPair::StringPair(const UnicodeString& _displayName, const UnicodeString& _id) - : displayName(_displayName) - , id(_id) +: displayName(_displayName) +, id(_id) { } -U_CAPI void U_EXPORT2 +U_CDECL_BEGIN +static void U_CALLCONV userv_deleteStringPair(void *obj) { - U_NAMESPACE_USE - delete (StringPair*) obj; + U_NAMESPACE_USE delete (StringPair*) obj; } +U_CDECL_END /* - ****************************************************************** - */ +****************************************************************** +*/ + +static UMutex lock = U_MUTEX_INITIALIZER; ICUService::ICUService() - : name() - , lock(0) - , timestamp(0) - , factories(NULL) - , serviceCache(NULL) - , idCache(NULL) - , dnCache(NULL) +: name() +, timestamp(0) +, factories(NULL) +, serviceCache(NULL) +, idCache(NULL) +, dnCache(NULL) { - umtx_init(&lock); } ICUService::ICUService(const UnicodeString& newName) - : name(newName) - , lock(0) - , timestamp(0) - , factories(NULL) - , serviceCache(NULL) - , idCache(NULL) - , dnCache(NULL) { - umtx_init(&lock); +: name(newName) +, timestamp(0) +, factories(NULL) +, serviceCache(NULL) +, idCache(NULL) +, dnCache(NULL) +{ } ICUService::~ICUService() - { - { - Mutex mutex(&lock); - clearCaches(); - delete factories; - factories = NULL; - } - umtx_destroy(&lock); +{ + { + Mutex mutex(&lock); + clearCaches(); + delete factories; + factories = NULL; + } } UObject* ICUService::get(const UnicodeString& descriptor, UErrorCode& status) const { - return get(descriptor, NULL, status); + return get(descriptor, NULL, status); } UObject* ICUService::get(const UnicodeString& descriptor, UnicodeString* actualReturn, UErrorCode& status) const { - UObject* result = NULL; + UObject* result = NULL; ICUServiceKey* key = createKey(&descriptor, status); if (key) { - result = getKey(*key, actualReturn, status); - delete key; + result = getKey(*key, actualReturn, status); + delete key; } - return result; + return result; } UObject* ICUService::getKey(ICUServiceKey& key, UErrorCode& status) const { - return getKey(key, NULL, status); + return getKey(key, NULL, status); } // this is a vector that subclasses of ICUService can override to further customize the result object @@ -392,7 +393,7 @@ ICUService::getKey(ICUServiceKey& key, UErrorCode& status) const UObject* ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const { - return getKey(key, actualReturn, NULL, status); + return getKey(key, actualReturn, NULL, status); } // make it possible to call reentrantly on systems that don't have reentrant mutexes. @@ -400,335 +401,336 @@ ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& // reentrantly even without knowing the thread. class XMutex : public UMemory { public: - inline XMutex(UMTX *mutex, UBool reentering) - : fMutex(mutex) - , fActive(!reentering) - { - if (fActive) umtx_lock(fMutex); - } - inline ~XMutex() { - if (fActive) umtx_unlock(fMutex); - } + inline XMutex(UMutex *mutex, UBool reentering) + : fMutex(mutex) + , fActive(!reentering) + { + if (fActive) umtx_lock(fMutex); + } + inline ~XMutex() { + if (fActive) umtx_unlock(fMutex); + } private: - UMTX *fMutex; - UBool fActive; + UMutex *fMutex; + UBool fActive; }; struct UVectorDeleter { - UVector* _obj; - UVectorDeleter() : _obj(NULL) {} - ~UVectorDeleter() { delete _obj; } + UVector* _obj; + UVectorDeleter() : _obj(NULL) {} + ~UVectorDeleter() { delete _obj; } }; // called only by factories, treat as private UObject* ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, const ICUServiceFactory* factory, UErrorCode& status) const { - if (U_FAILURE(status)) { - return NULL; - } - - if (isDefault()) { - return handleDefault(key, actualReturn, status); - } - - ICUService* ncthis = (ICUService*)this; // cast away semantic const - - CacheEntry* result = NULL; - { - // The factory list can't be modified until we're done, - // otherwise we might update the cache with an invalid result. - // The cache has to stay in synch with the factory list. - // ICU doesn't have monitors so we can't use rw locks, so - // we single-thread everything using this service, for now. - - // if factory is not null, we're calling from within the mutex, - // and since some unix machines don't have reentrant mutexes we - // need to make sure not to try to lock it again. - XMutex(&ncthis->lock, factory != NULL); - - if (serviceCache == NULL) { - ncthis->serviceCache = new Hashtable(status); - if (U_FAILURE(status)) { - delete serviceCache; + if (U_FAILURE(status)) { return NULL; - } - serviceCache->setValueDeleter(cacheDeleter); } - UnicodeString currentDescriptor; - UVectorDeleter cacheDescriptorList; - UBool putInCache = FALSE; + if (isDefault()) { + return handleDefault(key, actualReturn, status); + } - int32_t startIndex = 0; - int32_t limit = factories->size(); - UBool cacheResult = TRUE; + ICUService* ncthis = (ICUService*)this; // cast away semantic const - if (factory != NULL) { - for (int32_t i = 0; i < limit; ++i) { - if (factory == (const ICUServiceFactory*)factories->elementAt(i)) { - startIndex = i + 1; - break; - } - } - if (startIndex == 0) { - // throw new InternalError("Factory " + factory + "not registered with service: " + this); - status = U_ILLEGAL_ARGUMENT_ERROR; - return NULL; - } - cacheResult = FALSE; - } - - do { - currentDescriptor.remove(); - key.currentDescriptor(currentDescriptor); - result = (CacheEntry*)serviceCache->get(currentDescriptor); - if (result != NULL) { - break; - } - - // first test of cache failed, so we'll have to update - // the cache if we eventually succeed-- that is, if we're - // going to update the cache at all. - putInCache = TRUE; - - int32_t index = startIndex; - while (index < limit) { - ICUServiceFactory* f = (ICUServiceFactory*)factories->elementAt(index++); - UObject* service = f->create(key, this, status); - if (U_FAILURE(status)) { - delete service; - return NULL; + CacheEntry* result = NULL; + { + // The factory list can't be modified until we're done, + // otherwise we might update the cache with an invalid result. + // The cache has to stay in synch with the factory list. + // ICU doesn't have monitors so we can't use rw locks, so + // we single-thread everything using this service, for now. + + // if factory is not null, we're calling from within the mutex, + // and since some unix machines don't have reentrant mutexes we + // need to make sure not to try to lock it again. + XMutex mutex(&lock, factory != NULL); + + if (serviceCache == NULL) { + ncthis->serviceCache = new Hashtable(status); + if (ncthis->serviceCache == NULL) { + return NULL; + } + if (U_FAILURE(status)) { + delete serviceCache; + return NULL; + } + serviceCache->setValueDeleter(cacheDeleter); } - if (service != NULL) { - result = new CacheEntry(currentDescriptor, service); - if (result == NULL) { - delete service; - status = U_MEMORY_ALLOCATION_ERROR; - return NULL; - } - goto outerEnd; - } - } - - // prepare to load the cache with all additional ids that - // will resolve to result, assuming we'll succeed. We - // don't want to keep querying on an id that's going to - // fallback to the one that succeeded, we want to hit the - // cache the first time next goaround. - if (cacheDescriptorList._obj == NULL) { - cacheDescriptorList._obj = new UVector(uhash_deleteUnicodeString, NULL, 5, status); - if (U_FAILURE(status)) { - return NULL; - } - } - UnicodeString* idToCache = new UnicodeString(currentDescriptor); - if (idToCache == NULL || idToCache->isBogus()) { - status = U_MEMORY_ALLOCATION_ERROR; - return NULL; - } + UnicodeString currentDescriptor; + UVectorDeleter cacheDescriptorList; + UBool putInCache = FALSE; - cacheDescriptorList._obj->addElement(idToCache, status); - if (U_FAILURE(status)) { - return NULL; - } - } while (key.fallback()); - outerEnd: + int32_t startIndex = 0; + int32_t limit = factories->size(); + UBool cacheResult = TRUE; - if (result != NULL) { - if (putInCache && cacheResult) { - serviceCache->put(result->actualDescriptor, result, status); - if (U_FAILURE(status)) { - delete result; - return NULL; + if (factory != NULL) { + for (int32_t i = 0; i < limit; ++i) { + if (factory == (const ICUServiceFactory*)factories->elementAt(i)) { + startIndex = i + 1; + break; + } + } + if (startIndex == 0) { + // throw new InternalError("Factory " + factory + "not registered with service: " + this); + status = U_ILLEGAL_ARGUMENT_ERROR; + return NULL; + } + cacheResult = FALSE; } - if (cacheDescriptorList._obj != NULL) { - for (int32_t i = cacheDescriptorList._obj->size(); --i >= 0;) { - UnicodeString* desc = (UnicodeString*)cacheDescriptorList._obj->elementAt(i); - serviceCache->put(*desc, result, status); + do { + currentDescriptor.remove(); + key.currentDescriptor(currentDescriptor); + result = (CacheEntry*)serviceCache->get(currentDescriptor); + if (result != NULL) { + break; + } + + // first test of cache failed, so we'll have to update + // the cache if we eventually succeed-- that is, if we're + // going to update the cache at all. + putInCache = TRUE; + + int32_t index = startIndex; + while (index < limit) { + ICUServiceFactory* f = (ICUServiceFactory*)factories->elementAt(index++); + UObject* service = f->create(key, this, status); + if (U_FAILURE(status)) { + delete service; + return NULL; + } + if (service != NULL) { + result = new CacheEntry(currentDescriptor, service); + if (result == NULL) { + delete service; + status = U_MEMORY_ALLOCATION_ERROR; + return NULL; + } + + goto outerEnd; + } + } + + // prepare to load the cache with all additional ids that + // will resolve to result, assuming we'll succeed. We + // don't want to keep querying on an id that's going to + // fallback to the one that succeeded, we want to hit the + // cache the first time next goaround. + if (cacheDescriptorList._obj == NULL) { + cacheDescriptorList._obj = new UVector(uprv_deleteUObject, NULL, 5, status); + if (U_FAILURE(status)) { + return NULL; + } + } + UnicodeString* idToCache = new UnicodeString(currentDescriptor); + if (idToCache == NULL || idToCache->isBogus()) { + status = U_MEMORY_ALLOCATION_ERROR; + return NULL; + } + + cacheDescriptorList._obj->addElement(idToCache, status); if (U_FAILURE(status)) { - delete result; - return NULL; + return NULL; + } + } while (key.fallback()); +outerEnd: + + if (result != NULL) { + if (putInCache && cacheResult) { + serviceCache->put(result->actualDescriptor, result, status); + if (U_FAILURE(status)) { + delete result; + return NULL; + } + + if (cacheDescriptorList._obj != NULL) { + for (int32_t i = cacheDescriptorList._obj->size(); --i >= 0;) { + UnicodeString* desc = (UnicodeString*)cacheDescriptorList._obj->elementAt(i); + serviceCache->put(*desc, result, status); + if (U_FAILURE(status)) { + delete result; + return NULL; + } + + result->ref(); + cacheDescriptorList._obj->removeElementAt(i); + } + } } - result->ref(); - cacheDescriptorList._obj->removeElementAt(i); - } - } - } - - if (actualReturn != NULL) { - // strip null prefix - if (result->actualDescriptor.indexOf((UChar)0x2f) == 0) { // U+002f=slash (/) - actualReturn->remove(); - actualReturn->append(result->actualDescriptor, - 1, - result->actualDescriptor.length() - 1); - } else { - *actualReturn = result->actualDescriptor; - } + if (actualReturn != NULL) { + // strip null prefix + if (result->actualDescriptor.indexOf((UChar)0x2f) == 0) { // U+002f=slash (/) + actualReturn->remove(); + actualReturn->append(result->actualDescriptor, + 1, + result->actualDescriptor.length() - 1); + } else { + *actualReturn = result->actualDescriptor; + } + + if (actualReturn->isBogus()) { + status = U_MEMORY_ALLOCATION_ERROR; + delete result; + return NULL; + } + } - if (actualReturn->isBogus()) { - status = U_MEMORY_ALLOCATION_ERROR; - delete result; - return NULL; + UObject* service = cloneInstance(result->service); + if (putInCache && !cacheResult) { + delete result; + } + return service; } - } - - UObject* service = cloneInstance(result->service); - if (putInCache && !cacheResult) { - delete result; - } - return service; } - } - return handleDefault(key, actualReturn, status); + return handleDefault(key, actualReturn, status); } UObject* ICUService::handleDefault(const ICUServiceKey& /* key */, UnicodeString* /* actualIDReturn */, UErrorCode& /* status */) const { - return NULL; + return NULL; } - + UVector& ICUService::getVisibleIDs(UVector& result, UErrorCode& status) const { - return getVisibleIDs(result, NULL, status); + return getVisibleIDs(result, NULL, status); } UVector& ICUService::getVisibleIDs(UVector& result, const UnicodeString* matchID, UErrorCode& status) const { - result.removeAllElements(); - - if (U_FAILURE(status)) { - return result; - } - - ICUService * ncthis = (ICUService*)this; // cast away semantic const - { - Mutex mutex(&ncthis->lock); - const Hashtable* map = getVisibleIDMap(status); - if (map != NULL) { - ICUServiceKey* fallbackKey = createKey(matchID, status); - - for (int32_t pos = -1;;) { - const UHashElement* e = map->nextElement(pos); - if (e == NULL) { - break; - } + result.removeAllElements(); - const UnicodeString* id = (const UnicodeString*)e->key.pointer; - if (fallbackKey != NULL) { - if (!fallbackKey->isFallbackOf(*id)) { - continue; - } - } + if (U_FAILURE(status)) { + return result; + } - UnicodeString* idClone = new UnicodeString(*id); - if (idClone == NULL || idClone->isBogus()) { - delete idClone; - status = U_MEMORY_ALLOCATION_ERROR; - break; - } - result.addElement(idClone, status); - if (U_FAILURE(status)) { - delete idClone; - break; + { + Mutex mutex(&lock); + const Hashtable* map = getVisibleIDMap(status); + if (map != NULL) { + ICUServiceKey* fallbackKey = createKey(matchID, status); + + for (int32_t pos = -1;;) { + const UHashElement* e = map->nextElement(pos); + if (e == NULL) { + break; + } + + const UnicodeString* id = (const UnicodeString*)e->key.pointer; + if (fallbackKey != NULL) { + if (!fallbackKey->isFallbackOf(*id)) { + continue; + } + } + + UnicodeString* idClone = new UnicodeString(*id); + if (idClone == NULL || idClone->isBogus()) { + delete idClone; + status = U_MEMORY_ALLOCATION_ERROR; + break; + } + result.addElement(idClone, status); + if (U_FAILURE(status)) { + delete idClone; + break; + } + } + delete fallbackKey; } - } - delete fallbackKey; } - } - if (U_FAILURE(status)) { - result.removeAllElements(); - } - return result; + if (U_FAILURE(status)) { + result.removeAllElements(); + } + return result; } const Hashtable* ICUService::getVisibleIDMap(UErrorCode& status) const { - if (U_FAILURE(status)) return NULL; + if (U_FAILURE(status)) return NULL; - // must only be called when lock is already held + // must only be called when lock is already held - ICUService* ncthis = (ICUService*)this; // cast away semantic const - if (idCache == NULL) { - ncthis->idCache = new Hashtable(status); + ICUService* ncthis = (ICUService*)this; // cast away semantic const if (idCache == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - } else if (factories != NULL) { - for (int32_t pos = factories->size(); --pos >= 0;) { - ICUServiceFactory* f = (ICUServiceFactory*)factories->elementAt(pos); - f->updateVisibleIDs(*idCache, status); - } - if (U_FAILURE(status)) { - delete idCache; - ncthis->idCache = NULL; - } + ncthis->idCache = new Hashtable(status); + if (idCache == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + } else if (factories != NULL) { + for (int32_t pos = factories->size(); --pos >= 0;) { + ICUServiceFactory* f = (ICUServiceFactory*)factories->elementAt(pos); + f->updateVisibleIDs(*idCache, status); + } + if (U_FAILURE(status)) { + delete idCache; + ncthis->idCache = NULL; + } + } } - } - return idCache; + return idCache; } - + UnicodeString& ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result) const { - return getDisplayName(id, result, Locale::getDefault()); + return getDisplayName(id, result, Locale::getDefault()); } UnicodeString& ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result, const Locale& locale) const { - { - ICUService* ncthis = (ICUService*)this; // cast away semantic const - UErrorCode status = U_ZERO_ERROR; - Mutex mutex(&ncthis->lock); - const Hashtable* map = getVisibleIDMap(status); - if (map != NULL) { - ICUServiceFactory* f = (ICUServiceFactory*)map->get(id); - if (f != NULL) { - f->getDisplayName(id, locale, result); - return result; - } - - // fallback - UErrorCode status = U_ZERO_ERROR; - ICUServiceKey* fallbackKey = createKey(&id, status); - while (fallbackKey->fallback()) { - UnicodeString us; - fallbackKey->currentID(us); - f = (ICUServiceFactory*)map->get(us); - if (f != NULL) { - f->getDisplayName(id, locale, result); - delete fallbackKey; - return result; - } - } - delete fallbackKey; - } - } - result.setToBogus(); - return result; + { + UErrorCode status = U_ZERO_ERROR; + Mutex mutex(&lock); + const Hashtable* map = getVisibleIDMap(status); + if (map != NULL) { + ICUServiceFactory* f = (ICUServiceFactory*)map->get(id); + if (f != NULL) { + f->getDisplayName(id, locale, result); + return result; + } + + // fallback + UErrorCode status = U_ZERO_ERROR; + ICUServiceKey* fallbackKey = createKey(&id, status); + while (fallbackKey->fallback()) { + UnicodeString us; + fallbackKey->currentID(us); + f = (ICUServiceFactory*)map->get(us); + if (f != NULL) { + f->getDisplayName(id, locale, result); + delete fallbackKey; + return result; + } + } + delete fallbackKey; + } + } + result.setToBogus(); + return result; } UVector& ICUService::getDisplayNames(UVector& result, UErrorCode& status) const { - return getDisplayNames(result, Locale::getDefault(), NULL, status); + return getDisplayNames(result, Locale::getDefault(), NULL, status); } UVector& ICUService::getDisplayNames(UVector& result, const Locale& locale, UErrorCode& status) const { - return getDisplayNames(result, locale, NULL, status); + return getDisplayNames(result, locale, NULL, status); } UVector& @@ -737,232 +739,240 @@ ICUService::getDisplayNames(UVector& result, const UnicodeString* matchID, UErrorCode& status) const { - result.removeAllElements(); - if (U_SUCCESS(status)) { - ICUService* ncthis = (ICUService*)this; // cast away semantic const - Mutex mutex(&ncthis->lock); + result.removeAllElements(); + result.setDeleter(userv_deleteStringPair); + if (U_SUCCESS(status)) { + ICUService* ncthis = (ICUService*)this; // cast away semantic const + Mutex mutex(&lock); - if (dnCache != NULL && dnCache->locale != locale) { - delete dnCache; - ncthis->dnCache = NULL; - } + if (dnCache != NULL && dnCache->locale != locale) { + delete dnCache; + ncthis->dnCache = NULL; + } - if (dnCache == NULL) { - const Hashtable* m = getVisibleIDMap(status); - if (m != NULL) { - ncthis->dnCache = new DNCache(locale); if (dnCache == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - return result; - } + const Hashtable* m = getVisibleIDMap(status); + if (U_FAILURE(status)) { + return result; + } + ncthis->dnCache = new DNCache(locale); + if (dnCache == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + return result; + } - int32_t pos = 0; - const UHashElement* entry = NULL; - while ((entry = m->nextElement(pos)) != NULL) { - const UnicodeString* id = (const UnicodeString*)entry->key.pointer; - ICUServiceFactory* f = (ICUServiceFactory*)entry->value.pointer; - UnicodeString dname; - f->getDisplayName(*id, locale, dname); - if (dname.isBogus()) { - status = U_MEMORY_ALLOCATION_ERROR; - } else { - dnCache->cache.put(dname, (void*)id, status); // share pointer with visibleIDMap - if (U_SUCCESS(status)) { - continue; + int32_t pos = -1; + const UHashElement* entry = NULL; + while ((entry = m->nextElement(pos)) != NULL) { + const UnicodeString* id = (const UnicodeString*)entry->key.pointer; + ICUServiceFactory* f = (ICUServiceFactory*)entry->value.pointer; + UnicodeString dname; + f->getDisplayName(*id, locale, dname); + if (dname.isBogus()) { + status = U_MEMORY_ALLOCATION_ERROR; + } else { + dnCache->cache.put(dname, (void*)id, status); // share pointer with visibleIDMap + if (U_SUCCESS(status)) { + continue; + } + } + delete dnCache; + ncthis->dnCache = NULL; + return result; } - } - delete dnCache; - ncthis->dnCache = NULL; - return result; } - } } - } - ICUServiceKey* matchKey = createKey(matchID, status); - int32_t pos = 0; - const UHashElement *entry = NULL; - while ((entry = dnCache->cache.nextElement(pos)) != NULL) { - const UnicodeString* id = (const UnicodeString*)entry->value.pointer; - if (matchKey != NULL && !matchKey->isFallbackOf(*id)) { - continue; - } - const UnicodeString* dn = (const UnicodeString*)entry->key.pointer; - StringPair* sp = StringPair::create(*id, *dn, status); - result.addElement(sp, status); - if (U_FAILURE(status)) { - result.removeAllElements(); - break; + ICUServiceKey* matchKey = createKey(matchID, status); + /* To ensure that all elements in the hashtable are iterated, set pos to -1. + * nextElement(pos) will skip the position at pos and begin the iteration + * at the next position, which in this case will be 0. + */ + int32_t pos = -1; + const UHashElement *entry = NULL; + while ((entry = dnCache->cache.nextElement(pos)) != NULL) { + const UnicodeString* id = (const UnicodeString*)entry->value.pointer; + if (matchKey != NULL && !matchKey->isFallbackOf(*id)) { + continue; + } + const UnicodeString* dn = (const UnicodeString*)entry->key.pointer; + StringPair* sp = StringPair::create(*id, *dn, status); + result.addElement(sp, status); + if (U_FAILURE(status)) { + result.removeAllElements(); + break; + } } - } - delete matchKey; + delete matchKey; - return result; + return result; } URegistryKey ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UErrorCode& status) { - return registerInstance(objToAdopt, id, TRUE, status); + return registerInstance(objToAdopt, id, TRUE, status); } URegistryKey ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status) { - ICUServiceKey* key = createKey(&id, status); - if (key != NULL) { - UnicodeString canonicalID; - key->canonicalID(canonicalID); - delete key; + ICUServiceKey* key = createKey(&id, status); + if (key != NULL) { + UnicodeString canonicalID; + key->canonicalID(canonicalID); + delete key; - ICUServiceFactory* f = createSimpleFactory(objToAdopt, canonicalID, visible, status); - if (f != NULL) { - return registerFactory(f, status); + ICUServiceFactory* f = createSimpleFactory(objToAdopt, canonicalID, visible, status); + if (f != NULL) { + return registerFactory(f, status); + } } - } - delete objToAdopt; - return NULL; + delete objToAdopt; + return NULL; } ICUServiceFactory* ICUService::createSimpleFactory(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status) { - if (U_SUCCESS(status)) { - if ((objToAdopt != NULL) && (!id.isBogus())) { - return new SimpleFactory(objToAdopt, id, visible); + if (U_SUCCESS(status)) { + if ((objToAdopt != NULL) && (!id.isBogus())) { + return new SimpleFactory(objToAdopt, id, visible); + } + status = U_ILLEGAL_ARGUMENT_ERROR; } - status = U_ILLEGAL_ARGUMENT_ERROR; - } - return NULL; + return NULL; } URegistryKey ICUService::registerFactory(ICUServiceFactory* factoryToAdopt, UErrorCode& status) { - if (U_SUCCESS(status) && factoryToAdopt != NULL) { - Mutex mutex(&lock); + if (U_SUCCESS(status) && factoryToAdopt != NULL) { + Mutex mutex(&lock); - if (factories == NULL) { - factories = new UVector(deleteUObject, NULL, status); - if (U_FAILURE(status)) { - delete factories; - return NULL; - } - } - factories->insertElementAt(factoryToAdopt, 0, status); - if (U_SUCCESS(status)) { - clearCaches(); - } else { - delete factoryToAdopt; - factoryToAdopt = NULL; + if (factories == NULL) { + factories = new UVector(deleteUObject, NULL, status); + if (U_FAILURE(status)) { + delete factories; + return NULL; + } + } + factories->insertElementAt(factoryToAdopt, 0, status); + if (U_SUCCESS(status)) { + clearCaches(); + } else { + delete factoryToAdopt; + factoryToAdopt = NULL; + } } - } - if (factoryToAdopt != NULL) { - notifyChanged(); - } + if (factoryToAdopt != NULL) { + notifyChanged(); + } - return (URegistryKey)factoryToAdopt; + return (URegistryKey)factoryToAdopt; } UBool ICUService::unregister(URegistryKey rkey, UErrorCode& status) { - ICUServiceFactory *factory = (ICUServiceFactory*)rkey; - UBool result = FALSE; - if (factory != NULL && factories != NULL) { - Mutex mutex(&lock); + ICUServiceFactory *factory = (ICUServiceFactory*)rkey; + UBool result = FALSE; + if (factory != NULL && factories != NULL) { + Mutex mutex(&lock); - if (factories->removeElement(factory)) { - clearCaches(); - result = TRUE; - } else { - status = U_ILLEGAL_ARGUMENT_ERROR; - delete factory; + if (factories->removeElement(factory)) { + clearCaches(); + result = TRUE; + } else { + status = U_ILLEGAL_ARGUMENT_ERROR; + delete factory; + } } - } - if (result) { - notifyChanged(); - } - return result; + if (result) { + notifyChanged(); + } + return result; } void ICUService::reset() { - { - Mutex mutex(&lock); - reInitializeFactories(); - clearCaches(); - } - notifyChanged(); + { + Mutex mutex(&lock); + reInitializeFactories(); + clearCaches(); + } + notifyChanged(); } void ICUService::reInitializeFactories() { - if (factories != NULL) { - factories->removeAllElements(); - } + if (factories != NULL) { + factories->removeAllElements(); + } } UBool ICUService::isDefault() const { - return countFactories() == 0; + return countFactories() == 0; } ICUServiceKey* ICUService::createKey(const UnicodeString* id, UErrorCode& status) const { - return (U_FAILURE(status) || id == NULL) ? NULL : new ICUServiceKey(*id); + return (U_FAILURE(status) || id == NULL) ? NULL : new ICUServiceKey(*id); } void ICUService::clearCaches() { - // callers synchronize before use - ++timestamp; - delete dnCache; dnCache = NULL; - delete idCache; idCache = NULL; - delete serviceCache; serviceCache = NULL; + // callers synchronize before use + ++timestamp; + delete dnCache; + dnCache = NULL; + delete idCache; + idCache = NULL; + delete serviceCache; serviceCache = NULL; } void ICUService::clearServiceCache() { - // callers synchronize before use - delete serviceCache; serviceCache = NULL; + // callers synchronize before use + delete serviceCache; serviceCache = NULL; } UBool ICUService::acceptsListener(const EventListener& l) const { - return l.getDynamicClassID() == ServiceListener::getStaticClassID(); + return dynamic_cast(&l) != NULL; } void ICUService::notifyListener(EventListener& l) const { - ((ServiceListener&)l).serviceChanged(*this); + ((ServiceListener&)l).serviceChanged(*this); } UnicodeString& ICUService::getName(UnicodeString& result) const { - return result.append(name); + return result.append(name); } int32_t ICUService::countFactories() const { - return factories == NULL ? 0 : factories->size(); + return factories == NULL ? 0 : factories->size(); } int32_t ICUService::getTimestamp() const { - return timestamp; + return timestamp; } U_NAMESPACE_END