123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969 |
- // © 2016 and later: Unicode, Inc. and others.
- // License & terms of use: http://www.unicode.org/copyright.html
- /**
- *******************************************************************************
- * Copyright (C) 2001-2014, International Business Machines Corporation.
- * All Rights Reserved.
- *******************************************************************************
- */
- #include "unicode/utypes.h"
- #include "unicode/localpointer.h"
- #if !UCONFIG_NO_SERVICE
- #include "serv.h"
- #include "umutex.h"
- #undef SERVICE_REFCOUNT
- // in case we use the refcount stuff
- U_NAMESPACE_BEGIN
- /*
- ******************************************************************
- */
- const char16_t ICUServiceKey::PREFIX_DELIMITER = 0x002F; /* '/' */
- ICUServiceKey::ICUServiceKey(const UnicodeString& id)
- : _id(id) {
- }
- ICUServiceKey::~ICUServiceKey()
- {
- }
- const UnicodeString&
- ICUServiceKey::getID() const
- {
- return _id;
- }
- UnicodeString&
- ICUServiceKey::canonicalID(UnicodeString& result) const
- {
- return result.append(_id);
- }
- UnicodeString&
- ICUServiceKey::currentID(UnicodeString& result) const
- {
- return canonicalID(result);
- }
- UnicodeString&
- ICUServiceKey::currentDescriptor(UnicodeString& result) const
- {
- prefix(result);
- result.append(PREFIX_DELIMITER);
- return currentID(result);
- }
- UBool
- ICUServiceKey::fallback()
- {
- return false;
- }
- UBool
- ICUServiceKey::isFallbackOf(const UnicodeString& id) const
- {
- return id == _id;
- }
- UnicodeString&
- ICUServiceKey::prefix(UnicodeString& result) const
- {
- return result;
- }
- UnicodeString&
- ICUServiceKey::parsePrefix(UnicodeString& 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;
- }
- #ifdef SERVICE_DEBUG
- UnicodeString&
- ICUServiceKey::debug(UnicodeString& result) const
- {
- debugClass(result);
- result.append((UnicodeString)" id: ");
- result.append(_id);
- return result;
- }
- UnicodeString&
- ICUServiceKey::debugClass(UnicodeString& result) const
- {
- return result.append((UnicodeString)"ICUServiceKey");
- }
- #endif
- UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ICUServiceKey)
- /*
- ******************************************************************
- */
- ICUServiceFactory::~ICUServiceFactory() {}
- SimpleFactory::SimpleFactory(UObject* instanceToAdopt, const UnicodeString& id, UBool visible)
- : _instance(instanceToAdopt), _id(id), _visible(visible)
- {
- }
- SimpleFactory::~SimpleFactory()
- {
- 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);
- }
- }
- return nullptr;
- }
- void
- SimpleFactory::updateVisibleIDs(Hashtable& result, UErrorCode& status) const
- {
- 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;
- }
- #ifdef SERVICE_DEBUG
- UnicodeString&
- SimpleFactory::debug(UnicodeString& toAppendTo) const
- {
- debugClass(toAppendTo);
- toAppendTo.append((UnicodeString)" id: ");
- toAppendTo.append(_id);
- toAppendTo.append((UnicodeString)", visible: ");
- toAppendTo.append(_visible ? (UnicodeString)"T" : (UnicodeString)"F");
- return toAppendTo;
- }
- UnicodeString&
- SimpleFactory::debugClass(UnicodeString& toAppendTo) const
- {
- return toAppendTo.append((UnicodeString)"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.
- class CacheEntry : public UMemory {
- private:
- 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 resource has been released.
- */
- CacheEntry* unref() {
- if ((--refcount) == 0) {
- delete this;
- return nullptr;
- }
- 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;
- }
- };
- // Deleter for serviceCache
- U_CDECL_BEGIN
- static void U_CALLCONV
- cacheDeleter(void* obj) {
- U_NAMESPACE_USE ((CacheEntry*)obj)->unref();
- }
- U_CDECL_END
- /*
- ******************************************************************
- */
- class DNCache : public UMemory {
- public:
- 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 == nullptr || sp->isBogus()) {
- status = U_MEMORY_ALLOCATION_ERROR;
- delete sp;
- return nullptr;
- }
- return sp;
- }
- return nullptr;
- }
- UBool
- StringPair::isBogus() const {
- return displayName.isBogus() || id.isBogus();
- }
- StringPair::StringPair(const UnicodeString& _displayName,
- const UnicodeString& _id)
- : displayName(_displayName)
- , id(_id)
- {
- }
- U_CDECL_BEGIN
- static void U_CALLCONV
- userv_deleteStringPair(void *obj) {
- U_NAMESPACE_USE delete (StringPair*) obj;
- }
- U_CDECL_END
- /*
- ******************************************************************
- */
- static UMutex lock;
- ICUService::ICUService()
- : name()
- , timestamp(0)
- , factories(nullptr)
- , serviceCache(nullptr)
- , idCache(nullptr)
- , dnCache(nullptr)
- {
- }
- ICUService::ICUService(const UnicodeString& newName)
- : name(newName)
- , timestamp(0)
- , factories(nullptr)
- , serviceCache(nullptr)
- , idCache(nullptr)
- , dnCache(nullptr)
- {
- }
- ICUService::~ICUService()
- {
- {
- Mutex mutex(&lock);
- clearCaches();
- delete factories;
- factories = nullptr;
- }
- }
- UObject*
- ICUService::get(const UnicodeString& descriptor, UErrorCode& status) const
- {
- return get(descriptor, nullptr, status);
- }
- UObject*
- ICUService::get(const UnicodeString& descriptor, UnicodeString* actualReturn, UErrorCode& status) const
- {
- UObject* result = nullptr;
- ICUServiceKey* key = createKey(&descriptor, status);
- if (key) {
- result = getKey(*key, actualReturn, status);
- delete key;
- }
- return result;
- }
- UObject*
- ICUService::getKey(ICUServiceKey& key, UErrorCode& status) const
- {
- return getKey(key, nullptr, status);
- }
- // this is a vector that subclasses of ICUService can override to further customize the result object
- // before returning it. All other public get functions should call this one.
- UObject*
- ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const
- {
- return getKey(key, actualReturn, nullptr, status);
- }
- // make it possible to call reentrantly on systems that don't have reentrant mutexes.
- // we can use this simple approach since we know the situation where we're calling
- // reentrantly even without knowing the thread.
- class XMutex : public UMemory {
- public:
- inline XMutex(UMutex *mutex, UBool reentering)
- : fMutex(mutex)
- , fActive(!reentering)
- {
- if (fActive) umtx_lock(fMutex);
- }
- inline ~XMutex() {
- if (fActive) umtx_unlock(fMutex);
- }
- private:
- UMutex *fMutex;
- UBool fActive;
- };
- // 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 nullptr;
- }
- if (isDefault()) {
- return handleDefault(key, actualReturn, status);
- }
- ICUService* ncthis = (ICUService*)this; // cast away semantic const
- CacheEntry* result = nullptr;
- {
- // 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 != nullptr);
- if (serviceCache == nullptr) {
- ncthis->serviceCache = new Hashtable(status);
- if (ncthis->serviceCache == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
- if (U_FAILURE(status)) {
- delete serviceCache;
- return nullptr;
- }
- serviceCache->setValueDeleter(cacheDeleter);
- }
- UnicodeString currentDescriptor;
- LocalPointer<UVector> cacheDescriptorList;
- UBool putInCache = false;
- int32_t startIndex = 0;
- int32_t limit = factories->size();
- UBool cacheResult = true;
- if (factory != nullptr) {
- 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 nullptr;
- }
- cacheResult = false;
- }
- do {
- currentDescriptor.remove();
- key.currentDescriptor(currentDescriptor);
- result = (CacheEntry*)serviceCache->get(currentDescriptor);
- if (result != nullptr) {
- 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++);
- LocalPointer<UObject> service(f->create(key, this, status));
- if (U_FAILURE(status)) {
- return nullptr;
- }
- if (service.isValid()) {
- result = new CacheEntry(currentDescriptor, service.getAlias());
- if (result == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
- service.orphan(); // result now owns service.
- 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.isNull()) {
- cacheDescriptorList.adoptInsteadAndCheckErrorCode(new UVector(uprv_deleteUObject, nullptr, 5, status), status);
- if (U_FAILURE(status)) {
- return nullptr;
- }
- }
- LocalPointer<UnicodeString> idToCache(new UnicodeString(currentDescriptor), status);
- if (U_FAILURE(status)) {
- return nullptr;
- }
- if (idToCache->isBogus()) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return nullptr;
- }
- cacheDescriptorList->adoptElement(idToCache.orphan(), status);
- if (U_FAILURE(status)) {
- return nullptr;
- }
- } while (key.fallback());
- outerEnd:
- if (result != nullptr) {
- if (putInCache && cacheResult) {
- serviceCache->put(result->actualDescriptor, result, status);
- if (U_FAILURE(status)) {
- return nullptr;
- }
- if (cacheDescriptorList.isValid()) {
- for (int32_t i = cacheDescriptorList->size(); --i >= 0;) {
- UnicodeString* desc = (UnicodeString*)cacheDescriptorList->elementAt(i);
- serviceCache->put(*desc, result, status);
- if (U_FAILURE(status)) {
- return nullptr;
- }
- result->ref();
- cacheDescriptorList->removeElementAt(i);
- }
- }
- }
- if (actualReturn != nullptr) {
- // strip null prefix
- if (result->actualDescriptor.indexOf((char16_t)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 nullptr;
- }
- }
- UObject* service = cloneInstance(result->service);
- if (putInCache && !cacheResult) {
- delete result;
- }
- return service;
- }
- }
- return handleDefault(key, actualReturn, status);
- }
- UObject*
- ICUService::handleDefault(const ICUServiceKey& /* key */, UnicodeString* /* actualIDReturn */, UErrorCode& /* status */) const
- {
- return nullptr;
- }
- UVector&
- ICUService::getVisibleIDs(UVector& result, UErrorCode& status) const {
- return getVisibleIDs(result, nullptr, status);
- }
- UVector&
- ICUService::getVisibleIDs(UVector& result, const UnicodeString* matchID, UErrorCode& status) const
- {
- result.removeAllElements();
- if (U_FAILURE(status)) {
- return result;
- }
- UObjectDeleter *savedDeleter = result.setDeleter(uprv_deleteUObject);
- {
- Mutex mutex(&lock);
- const Hashtable* map = getVisibleIDMap(status);
- if (map != nullptr) {
- ICUServiceKey* fallbackKey = createKey(matchID, status);
- for (int32_t pos = UHASH_FIRST; U_SUCCESS(status); ) {
- const UHashElement* e = map->nextElement(pos);
- if (e == nullptr) {
- break;
- }
- const UnicodeString* id = (const UnicodeString*)e->key.pointer;
- if (fallbackKey != nullptr) {
- if (!fallbackKey->isFallbackOf(*id)) {
- continue;
- }
- }
- LocalPointer<UnicodeString> idClone(id->clone(), status);
- result.adoptElement(idClone.orphan(), status);
- }
- delete fallbackKey;
- }
- }
- if (U_FAILURE(status)) {
- result.removeAllElements();
- }
- result.setDeleter(savedDeleter);
- return result;
- }
- const Hashtable*
- ICUService::getVisibleIDMap(UErrorCode& status) const {
- if (U_FAILURE(status)) return nullptr;
- // must only be called when lock is already held
- ICUService* ncthis = (ICUService*)this; // cast away semantic const
- if (idCache == nullptr) {
- ncthis->idCache = new Hashtable(status);
- if (idCache == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- } else if (factories != nullptr) {
- 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 = nullptr;
- }
- }
- }
- return idCache;
- }
- UnicodeString&
- ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result) const
- {
- return getDisplayName(id, result, Locale::getDefault());
- }
- UnicodeString&
- ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result, const Locale& locale) const
- {
- {
- UErrorCode status = U_ZERO_ERROR;
- Mutex mutex(&lock);
- const Hashtable* map = getVisibleIDMap(status);
- if (map != nullptr) {
- ICUServiceFactory* f = (ICUServiceFactory*)map->get(id);
- if (f != nullptr) {
- f->getDisplayName(id, locale, result);
- return result;
- }
- // fallback
- status = U_ZERO_ERROR;
- ICUServiceKey* fallbackKey = createKey(&id, status);
- while (fallbackKey != nullptr && fallbackKey->fallback()) {
- UnicodeString us;
- fallbackKey->currentID(us);
- f = (ICUServiceFactory*)map->get(us);
- if (f != nullptr) {
- 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(), nullptr, status);
- }
- UVector&
- ICUService::getDisplayNames(UVector& result, const Locale& locale, UErrorCode& status) const
- {
- return getDisplayNames(result, locale, nullptr, status);
- }
- UVector&
- ICUService::getDisplayNames(UVector& result,
- const Locale& locale,
- const UnicodeString* matchID,
- UErrorCode& status) const
- {
- result.removeAllElements();
- result.setDeleter(userv_deleteStringPair);
- if (U_SUCCESS(status)) {
- ICUService* ncthis = (ICUService*)this; // cast away semantic const
- Mutex mutex(&lock);
- if (dnCache != nullptr && dnCache->locale != locale) {
- delete dnCache;
- ncthis->dnCache = nullptr;
- }
- if (dnCache == nullptr) {
- const Hashtable* m = getVisibleIDMap(status);
- if (U_FAILURE(status)) {
- return result;
- }
- ncthis->dnCache = new DNCache(locale);
- if (dnCache == nullptr) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return result;
- }
- int32_t pos = UHASH_FIRST;
- const UHashElement* entry = nullptr;
- while ((entry = m->nextElement(pos)) != nullptr) {
- 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 = nullptr;
- return result;
- }
- }
- }
- 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 = UHASH_FIRST;
- const UHashElement *entry = nullptr;
- while ((entry = dnCache->cache.nextElement(pos)) != nullptr) {
- const UnicodeString* id = (const UnicodeString*)entry->value.pointer;
- if (matchKey != nullptr && !matchKey->isFallbackOf(*id)) {
- continue;
- }
- const UnicodeString* dn = (const UnicodeString*)entry->key.pointer;
- StringPair* sp = StringPair::create(*id, *dn, status);
- result.adoptElement(sp, status);
- if (U_FAILURE(status)) {
- result.removeAllElements();
- break;
- }
- }
- delete matchKey;
- return result;
- }
- URegistryKey
- ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UErrorCode& 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 != nullptr) {
- UnicodeString canonicalID;
- key->canonicalID(canonicalID);
- delete key;
- ICUServiceFactory* f = createSimpleFactory(objToAdopt, canonicalID, visible, status);
- if (f != nullptr) {
- return registerFactory(f, status);
- }
- }
- delete objToAdopt;
- return nullptr;
- }
- ICUServiceFactory*
- ICUService::createSimpleFactory(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status)
- {
- if (U_SUCCESS(status)) {
- if ((objToAdopt != nullptr) && (!id.isBogus())) {
- return new SimpleFactory(objToAdopt, id, visible);
- }
- status = U_ILLEGAL_ARGUMENT_ERROR;
- }
- return nullptr;
- }
- URegistryKey
- ICUService::registerFactory(ICUServiceFactory* factoryToAdopt, UErrorCode& status)
- {
- LocalPointer<ICUServiceFactory>lpFactoryToAdopt(factoryToAdopt);
- if (U_FAILURE(status) || factoryToAdopt == nullptr) {
- return nullptr;
- }
- {
- Mutex mutex(&lock);
- if (factories == nullptr) {
- LocalPointer<UVector> lpFactories(new UVector(uprv_deleteUObject, nullptr, status), status);
- if (U_FAILURE(status)) {
- return nullptr;
- }
- factories = lpFactories.orphan();
- }
- factories->insertElementAt(lpFactoryToAdopt.orphan(), 0, status);
- if (U_SUCCESS(status)) {
- clearCaches();
- }
- } // Close of mutex lock block.
- if (U_SUCCESS(status)) {
- notifyChanged();
- return (URegistryKey)factoryToAdopt;
- } else {
- return nullptr;
- }
- }
- UBool
- ICUService::unregister(URegistryKey rkey, UErrorCode& status)
- {
- ICUServiceFactory *factory = (ICUServiceFactory*)rkey;
- UBool result = false;
- if (factory != nullptr && factories != nullptr) {
- Mutex mutex(&lock);
- if (factories->removeElement(factory)) {
- clearCaches();
- result = true;
- } else {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- delete factory;
- }
- }
- if (result) {
- notifyChanged();
- }
- return result;
- }
- void
- ICUService::reset()
- {
- {
- Mutex mutex(&lock);
- reInitializeFactories();
- clearCaches();
- }
- notifyChanged();
- }
- void
- ICUService::reInitializeFactories()
- {
- if (factories != nullptr) {
- factories->removeAllElements();
- }
- }
- UBool
- ICUService::isDefault() const
- {
- return countFactories() == 0;
- }
- ICUServiceKey*
- ICUService::createKey(const UnicodeString* id, UErrorCode& status) const
- {
- return (U_FAILURE(status) || id == nullptr) ? nullptr : new ICUServiceKey(*id);
- }
- void
- ICUService::clearCaches()
- {
- // callers synchronize before use
- ++timestamp;
- delete dnCache;
- dnCache = nullptr;
- delete idCache;
- idCache = nullptr;
- delete serviceCache; serviceCache = nullptr;
- }
- void
- ICUService::clearServiceCache()
- {
- // callers synchronize before use
- delete serviceCache; serviceCache = nullptr;
- }
- UBool
- ICUService::acceptsListener(const EventListener& l) const
- {
- return dynamic_cast<const ServiceListener*>(&l) != nullptr;
- }
- void
- ICUService::notifyListener(EventListener& l) const
- {
- (static_cast<ServiceListener&>(l)).serviceChanged(*this);
- }
- UnicodeString&
- ICUService::getName(UnicodeString& result) const
- {
- return result.append(name);
- }
- int32_t
- ICUService::countFactories() const
- {
- return factories == nullptr ? 0 : factories->size();
- }
- int32_t
- ICUService::getTimestamp() const
- {
- return timestamp;
- }
- U_NAMESPACE_END
- /* UCONFIG_NO_SERVICE */
- #endif
|